# How to Integrate Replit with TikTok Ads

- Tool: Replit
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: March 2026

## TL;DR

To integrate Replit with TikTok Ads, register a TikTok Marketing API developer app to get your App ID, Secret, and access token, store them in Replit Secrets (lock icon 🔒), and call the TikTok Marketing API from your Python or Node.js backend to create campaigns, manage ad groups, upload creatives, and retrieve performance analytics. Deploy with Autoscale for on-demand ad operations.

## Why Connect Replit to TikTok Ads?

TikTok's advertising platform has grown into a critical performance marketing channel, particularly for brands targeting audiences under 35. The TikTok Marketing API enables developers to automate campaign management at scale: creating campaigns programmatically, adjusting bids based on performance data, uploading creative assets in bulk, and building custom dashboards that aggregate TikTok data alongside other ad platforms.

The most impactful use cases for Replit integration are performance reporting automation and bulk campaign management. A Replit backend can pull daily TikTok ad metrics, aggregate them with Facebook and Google Ads data, and push combined reports to Smartsheet or Slack — eliminating the manual dashboard-checking routine for marketing teams. Alternatively, it can create campaigns from a structured template when a new product launches, setting targeting, budget, and creative parameters automatically.

TikTok's Marketing API uses OAuth 2.0 for authentication, but for single-advertiser automation you can generate a long-lived access token from the developer portal that does not require repeated OAuth authorization. This token, stored in Replit Secrets (lock icon 🔒 in the sidebar), authenticates all API calls from your server-side code. Never expose the access token in client-side JavaScript — it provides full access to your TikTok Ads account including the ability to spend budget.

## Before you start

- A Replit account with a Python or Node.js project created
- A TikTok Ads Manager account with an active advertiser account (advertiser_id)
- A TikTok developer account at business.tiktok.com/portal to create a Marketing API app
- Basic familiarity with REST APIs, ad platform concepts (campaign/ad group/ad hierarchy), and JSON
- Node.js 18+ or Python 3.10+ (both available on Replit by default)

## Step-by-step guide

### 1. Register a TikTok Marketing API App and Get Credentials

Navigate to the TikTok Marketing API portal at business.tiktok.com/portal. Sign in with your TikTok business account. In the developer console, click 'Create App' and fill in the application details:

- App Name: 'Replit Marketing Integration' or similar
- App Type: 'Standard API' for most use cases
- Industry and description as appropriate
- Redirect URI: your Replit app URL for OAuth callbacks (e.g., https://your-repl.repl.co/oauth/callback)

After creating the app, navigate to its settings. You will find:
- App ID: your application identifier
- App Secret: your application secret (keep this confidential)

For generating an access token for your own advertiser account without going through the full OAuth flow each time, TikTok provides a long-lived token generation option in the developer portal. Look for 'Generate Token' or 'Access Token' in the app settings. This generates a token that is valid for 24 hours (some configurations provide longer-lived tokens).

Also note your Advertiser ID — this is visible in your TikTok Ads Manager URL when you are logged in (it looks like a long numeric ID). You will need this for all API calls that manage campaigns.

**Expected result:** You have a TikTok App ID, App Secret, access token, and advertiser ID ready to add to Replit Secrets.

### 2. Store TikTok Marketing API Credentials in Replit Secrets

Open your Replit project and click the lock icon 🔒 in the left sidebar to open the Secrets pane. Add the following secrets:

- Key: TIKTOK_APP_ID — Value: your TikTok Marketing API App ID
- Key: TIKTOK_APP_SECRET — Value: your App Secret
- Key: TIKTOK_ACCESS_TOKEN — Value: your access token
- Key: TIKTOK_ADVERTISER_ID — Value: your TikTok Ads advertiser ID

Click 'Add Secret' after each entry. Replit encrypts these values and injects them as environment variables at runtime. They never appear in your file tree or Git history.

Access them in Python with os.environ['TIKTOK_ACCESS_TOKEN'] and in Node.js with process.env.TIKTOK_ACCESS_TOKEN. Restart your Repl after adding secrets.

The access token provides full access to your TikTok Ads account, including the ability to create campaigns, spend budget, and read all advertising data. Treat it with the same care as a production database password. Never commit it to source code.

**Expected result:** TIKTOK_APP_ID, TIKTOK_APP_SECRET, TIKTOK_ACCESS_TOKEN, and TIKTOK_ADVERTISER_ID appear in the Replit Secrets pane.

### 3. Create Campaigns and Retrieve Analytics with Python

The TikTok Marketing API base URL is https://business-api.tiktok.com/open_api/v1.3. All requests use the Access-Token header (not Authorization: Bearer — this is a TikTok-specific convention). The advertiser_id is passed as a query parameter or in the request body depending on the endpoint.

TikTok Ads are organized in a three-level hierarchy: Campaign (objective and total budget) > Ad Group (targeting, schedule, bid) > Ad (creative — video + text). You create them in this order.

The Python module below shows creating a campaign, retrieving campaign performance data, and managing ad group status. Install requests with pip install requests.

```
import os
import requests
from datetime import datetime, timedelta
from typing import Optional

ACCESS_TOKEN = os.environ["TIKTOK_ACCESS_TOKEN"]
ADVERTISER_ID = os.environ["TIKTOK_ADVERTISER_ID"]
BASE_URL = "https://business-api.tiktok.com/open_api/v1.3"

# TikTok uses Access-Token header, not Authorization: Bearer
HEADERS = {
    "Access-Token": ACCESS_TOKEN,
    "Content-Type": "application/json"
}

def api_get(endpoint: str, params: dict = None) -> dict:
    """Make a GET request to the TikTok Marketing API."""
    if params is None:
        params = {}
    params['advertiser_id'] = ADVERTISER_ID
    response = requests.get(f"{BASE_URL}/{endpoint}", params=params, headers=HEADERS)
    response.raise_for_status()
    data = response.json()
    if data.get('code') != 0:
        raise Exception(f"TikTok API error: {data.get('message')} (code: {data.get('code')})")
    return data.get('data', {})

def api_post(endpoint: str, payload: dict) -> dict:
    """Make a POST request to the TikTok Marketing API."""
    payload['advertiser_id'] = ADVERTISER_ID
    response = requests.post(f"{BASE_URL}/{endpoint}", json=payload, headers=HEADERS)
    response.raise_for_status()
    data = response.json()
    if data.get('code') != 0:
        raise Exception(f"TikTok API error: {data.get('message')} (code: {data.get('code')})")
    return data.get('data', {})

def create_campaign(
    name: str,
    objective: str = "TRAFFIC",  # AWARENESS, TRAFFIC, APP_PROMOTION, LEAD_GENERATION, CONVERSIONS
    budget_mode: str = "BUDGET_MODE_INFINITE",
    budget: float = 0
) -> dict:
    """
    Create a TikTok ad campaign.
    Returns campaign data including campaign_id.
    """
    payload = {
        "campaign_name": name,
        "objective_type": objective,
        "budget_mode": budget_mode,
        "operation_status": "DISABLE"  # Start paused, enable manually after review
    }
    if budget > 0:
        payload["budget"] = budget
        payload["budget_mode"] = "BUDGET_MODE_DAY"

    return api_post("campaign/create/", payload)

def get_campaigns(status_filter: str = "ALL") -> list:
    """List all campaigns for the advertiser."""
    data = api_get("campaign/get/", {"primary_status": status_filter})
    return data.get('list', [])

def get_campaign_report(
    campaign_ids: list,
    start_date: str,  # YYYY-MM-DD
    end_date: str,
    metrics: list = None
) -> list:
    """
    Retrieve performance metrics for specified campaigns.
    Default metrics: impressions, clicks, spend, conversions, ROAS.
    """
    if metrics is None:
        metrics = [
            "campaign_name", "spend", "impressions", "clicks",
            "ctr", "cpc", "conversions", "cost_per_conversion",
            "total_complete_payment_roas"
        ]
    payload = {
        "report_type": "BASIC",
        "dimensions": ["campaign_id"],
        "metrics": metrics,
        "data_level": "AUCTION_CAMPAIGN",
        "start_date": start_date,
        "end_date": end_date,
        "filtering": [
            {"field_name": "campaign_ids", "filter_type": "IN",
             "filter_value": str(campaign_ids)}
        ],
        "page_size": 100
    }
    return api_post("report/integrated/get/", payload).get('list', [])

def update_ad_group_status(ad_group_id: str, status: str) -> dict:
    """Enable or pause an ad group. status: 'ENABLE' or 'DISABLE'"""
    return api_post("adgroup/status/update/", {
        "adgroup_ids": [ad_group_id],
        "operation_status": status
    })

# Example usage
if __name__ == "__main__":
    # List all campaigns
    campaigns = get_campaigns()
    print(f"Total campaigns: {len(campaigns)}")
    for c in campaigns[:5]:
        print(f"  {c['campaign_id']}: {c['campaign_name']} [{c['primary_status']}]")

    # Get last 7 days performance report
    today = datetime.now()
    start = (today - timedelta(days=7)).strftime("%Y-%m-%d")
    end = today.strftime("%Y-%m-%d")

    if campaigns:
        campaign_ids = [c['campaign_id'] for c in campaigns[:5]]
        report = get_campaign_report(campaign_ids, start, end)
        for row in report:
            dims = row.get('dimensions', {})
            metrics = row.get('metrics', {})
            print(f"Campaign {dims.get('campaign_id')}: "
                  f"Spend=${metrics.get('spend', 0)} | "
                  f"Impressions={metrics.get('impressions', 0)} | "
                  f"ROAS={metrics.get('total_complete_payment_roas', 'N/A')}")
```

**Expected result:** Running the Python script lists your TikTok campaigns and prints a 7-day performance summary with spend and impression data.

### 4. Build a Campaign Management Server with Node.js

A Node.js Express server provides endpoints for creating campaigns on demand and retrieving performance reports. This is useful when integrating TikTok Ads management into a marketing dashboard or triggering campaign creation from other business systems.

The server handles the TikTok-specific response format (all responses return HTTP 200 with a code field) and exposes clean endpoints for frontend or other service consumption. Install dependencies with npm install express axios.

```
const express = require('express');
const axios = require('axios');

const app = express();
app.use(express.json());

const ACCESS_TOKEN = process.env.TIKTOK_ACCESS_TOKEN;
const ADVERTISER_ID = process.env.TIKTOK_ADVERTISER_ID;
const BASE_URL = 'https://business-api.tiktok.com/open_api/v1.3';

const ttHeaders = {
  'Access-Token': ACCESS_TOKEN,
  'Content-Type': 'application/json'
};

async function tiktokGet(endpoint, params = {}) {
  const response = await axios.get(`${BASE_URL}/${endpoint}`, {
    headers: ttHeaders,
    params: { ...params, advertiser_id: ADVERTISER_ID }
  });
  const { code, message, data } = response.data;
  if (code !== 0) throw new Error(`TikTok API error: ${message} (code: ${code})`);
  return data;
}

async function tiktokPost(endpoint, payload) {
  const response = await axios.post(`${BASE_URL}/${endpoint}`, {
    ...payload,
    advertiser_id: ADVERTISER_ID
  }, { headers: ttHeaders });
  const { code, message, data } = response.data;
  if (code !== 0) throw new Error(`TikTok API error: ${message} (code: ${code})`);
  return data;
}

// GET /campaigns — list all campaigns
app.get('/campaigns', async (req, res) => {
  try {
    const data = await tiktokGet('campaign/get/');
    res.json({
      total: data.page_info?.total_number || 0,
      campaigns: data.list || []
    });
  } catch (error) {
    console.error('TikTok error:', error.message);
    res.status(500).json({ error: error.message });
  }
});

// POST /campaigns — create a new campaign
app.post('/campaigns', async (req, res) => {
  const { name, objective, dailyBudget } = req.body;
  if (!name || !objective) {
    return res.status(400).json({ error: 'name and objective are required' });
  }
  try {
    const payload = {
      campaign_name: name,
      objective_type: objective,
      operation_status: 'DISABLE'  // Start paused for review
    };
    if (dailyBudget) {
      payload.budget = dailyBudget;
      payload.budget_mode = 'BUDGET_MODE_DAY';
    } else {
      payload.budget_mode = 'BUDGET_MODE_INFINITE';
    }
    const data = await tiktokPost('campaign/create/', payload);
    res.json({ success: true, campaignId: data.campaign_id });
  } catch (error) {
    console.error('TikTok error:', error.message);
    res.status(500).json({ error: error.message });
  }
});

// GET /report?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD — performance report
app.get('/report', async (req, res) => {
  const { startDate, endDate } = req.query;
  if (!startDate || !endDate) {
    return res.status(400).json({ error: 'startDate and endDate query params required (YYYY-MM-DD)' });
  }
  try {
    const data = await tiktokPost('report/integrated/get/', {
      report_type: 'BASIC',
      dimensions: ['campaign_id'],
      metrics: ['campaign_name', 'spend', 'impressions', 'clicks', 'ctr', 'cpc', 'conversions'],
      data_level: 'AUCTION_CAMPAIGN',
      start_date: startDate,
      end_date: endDate,
      page_size: 50
    });
    res.json({ rows: data.list || [] });
  } catch (error) {
    console.error('TikTok error:', error.message);
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, '0.0.0.0', () => {
  console.log('TikTok Ads integration server running on port 3000');
});
```

**Expected result:** The Express server starts on port 3000. GET /campaigns lists your TikTok campaigns and GET /report returns performance metrics for the specified date range.

## Best practices

- Always store TIKTOK_ACCESS_TOKEN and TIKTOK_ADVERTISER_ID in Replit Secrets — access tokens provide full account access including budget spending
- Use 'Access-Token' as the header name for authentication, not 'Authorization: Bearer' — this is TikTok-specific and a common integration mistake
- Check the 'code' field in every API response regardless of HTTP status — TikTok returns errors as HTTP 200 with a non-zero code value
- Create campaigns in DISABLE (paused) status and review them in Ads Manager before enabling, to ensure creative compliance before budget is spent
- Monitor token expiry and implement automated token refresh before expiry to prevent integration downtime
- Use sandbox advertiser accounts for all testing and development — production campaigns spend real money
- Batch reporting requests to retrieve all campaign metrics in a single API call with multiple dimensions rather than making per-campaign calls
- Deploy on Replit Autoscale for HTTP-triggered campaign management and use Reserved VM for scheduled performance monitoring and pacing adjustment scripts

## Use cases

### Automated Campaign Creation on Product Launch

When a new product is launched in your e-commerce system, a Replit backend automatically creates a TikTok campaign with optimized settings, configures ad groups targeting relevant interest categories and demographics, and uploads product video creatives — launching the campaign minutes after product creation without manual Ad Manager setup.

Prompt example:

```
Build a Flask endpoint that receives a product launch webhook, creates a TikTok Awareness campaign via the Marketing API with a daily budget and target audience based on product category, and returns the campaign ID and initial status.
```

### Cross-Platform Performance Dashboard

A Replit scheduled job pulls TikTok ad performance data (impressions, clicks, conversions, spend, ROAS) daily across all active campaigns, normalizes it alongside Facebook and Google Ads data, and writes the combined report to a Smartsheet or sends it as a formatted Slack message to the marketing team.

Prompt example:

```
Create a Python script that fetches the last 7 days of TikTok ad metrics from the Marketing API, aggregates spend and ROAS by campaign, formats the results as a readable report, and posts it to a Slack channel using the TIKTOK_ACCESS_TOKEN and SLACK_BOT_TOKEN from Replit Secrets.
```

### Budget Pacing and Bid Optimization

A Replit service monitors TikTok campaign spend throughout the day and automatically adjusts daily budgets or bids based on pacing rules — increasing budgets for high-performing ad groups when ROAS exceeds threshold and pausing underperforming creatives — without requiring manual intervention from the media buyer.

Prompt example:

```
Write a Python script that retrieves TikTok ad group performance every 4 hours, identifies ad groups with ROAS below 1.5, pauses those ad groups via the API, and sends an alert with the paused ad groups list to a monitoring Slack channel.
```

## Troubleshooting

### All API responses return HTTP 200 but with code 40001 or 40002 and 'invalid access token'

Cause: The access token has expired, was revoked, or is not included in the correct header. TikTok uses 'Access-Token' as the header name, not 'Authorization: Bearer'.

Solution: Verify TIKTOK_ACCESS_TOKEN is set in Replit Secrets and that the header is set as 'Access-Token: YOUR_TOKEN' (not Authorization). If the token has expired, generate a new one from the TikTok developer portal or implement token refresh using your App ID and Secret.

```
# Correct TikTok header format
HEADERS = {
    "Access-Token": os.environ["TIKTOK_ACCESS_TOKEN"],  # NOT 'Authorization: Bearer'
    "Content-Type": "application/json"
}
```

### Campaign creation returns code 40300 'permission denied' or 'no permission to operate'

Cause: The access token does not have permission to perform write operations on the specified advertiser account, or the advertiser_id belongs to a different account than the token was issued for.

Solution: Verify that TIKTOK_ADVERTISER_ID matches the advertiser account associated with your access token. In TikTok Ads Manager, the advertiser ID is visible in account settings. If your token was generated for a sandbox account, it cannot be used for production campaigns.

### Report endpoint returns an empty list even though campaigns have been running

Cause: The date range is incorrect (future dates or too far in the past), the campaign IDs in the filter are wrong, or the report_type/data_level combination does not match the campaigns' buying type.

Solution: Verify the date range is in the past and in YYYY-MM-DD format. Remove the campaign_ids filter to get all campaigns first, then narrow down. Use 'AUCTION' campaigns with data_level 'AUCTION_CAMPAIGN' for standard campaigns, or 'REACH_FREQUENCY' for reservation campaigns.

```
# Start without filters to verify data is available
payload = {
    "report_type": "BASIC",
    "dimensions": ["campaign_id"],
    "metrics": ["campaign_name", "spend", "impressions"],
    "data_level": "AUCTION_CAMPAIGN",
    "start_date": "2026-03-01",  # Use a known past date
    "end_date": "2026-03-30",
    "page_size": 100
    # No filtering initially
}
```

### Rate limit error: code 40100 or HTTP 429 after many requests

Cause: TikTok Marketing API has rate limits of approximately 100 requests per minute per access token for most endpoints. Bulk operations that loop through many campaigns or ad groups can hit this limit quickly.

Solution: Add delays between batches of API calls and implement exponential backoff for 429 responses. For reporting, use the report endpoint with multiple dimensions in a single call rather than querying each campaign separately.

```
import time

def api_post_with_retry(endpoint, payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            return api_post(endpoint, payload)
        except Exception as e:
            if '40100' in str(e) or '429' in str(e):
                wait_time = (2 ** attempt) * 5  # 5s, 10s, 20s
                print(f"Rate limited. Waiting {wait_time}s before retry...")
                time.sleep(wait_time)
            else:
                raise
    raise Exception("Max retries exceeded")
```

## Frequently asked questions

### How do I connect Replit to TikTok Ads?

Register a developer app at business.tiktok.com/portal, generate an access token, and add TIKTOK_ACCESS_TOKEN and TIKTOK_ADVERTISER_ID to Replit Secrets (lock icon 🔒 in the sidebar). Use the 'Access-Token' header (not Authorization) when calling the TikTok Marketing API from your Python or Node.js backend.

### Does the TikTok Marketing API require OAuth for every request?

For single-advertiser automation, you can generate a long-lived access token from the TikTok developer portal that authenticates API calls without repeated OAuth flows. Full OAuth 2.0 is needed when building apps where multiple advertisers connect their TikTok accounts to your platform.

### Why do TikTok API calls return HTTP 200 even when there is an error?

TikTok Marketing API uses HTTP 200 for all responses and communicates errors via the 'code' field in the JSON response body. A code of 0 means success; any other code indicates an error. Always check the 'code' and 'message' fields in every response.

### Can I retrieve TikTok ad performance data from Replit for custom reporting?

Yes. Use the POST /report/integrated/get/ endpoint with your date range, dimensions (campaign_id, ad_group_id, or ad_id), and desired metrics (spend, impressions, clicks, conversions, ROAS). The endpoint returns structured data you can aggregate into custom dashboards or push to other tools.

### What TikTok ad campaign objectives can I create via the API?

The Marketing API supports all TikTok campaign objectives: REACH, VIDEO_VIEWS, TRAFFIC, APP_PROMOTION, LEAD_GENERATION, CONVERSIONS, CATALOG_SALES, and COMMUNITY_INTERACTION. Use the objective_type parameter when creating campaigns.

### What deployment type should I use on Replit for TikTok Ads integrations?

Use Autoscale deployment for HTTP-triggered endpoints that create campaigns or respond to external events. Use Reserved VM for scheduled optimization jobs that check performance metrics every few hours and automatically adjust bids or pause underperforming ad groups.

---

Source: https://www.rapidevelopers.com/replit-integration/tiktok-ads
© RapidDev — https://www.rapidevelopers.com/replit-integration/tiktok-ads
