📊 TikTok Ads - Campaigns & Analytics
📖 Overview
The campaigns and analytics module provides comprehensive access to TikTok advertising campaigns, ad groups, individual ads, and integrated performance reports. Supports listing operations with pagination and advanced analytics reporting with custom dimensions, metrics, and filtering.
Source Files:
- Controller:
external/Integrations/TikTok/Controllers/analytics.js - Route:
external/Integrations/TikTok/Routes/analytics.js - Provider:
external/Integrations/TikTok/providers/tiktok-analytics.js - Constants:
external/Integrations/TikTok/constants/constants.js
External API: TikTok Marketing API - Campaign Management & Integrated Reporting
🗄️ Collections Used
tiktok.tokens
- Operations: Read
- Model:
shared/models/tik-tok-token.js - Usage Context: Retrieve access token for API authentication
analytics_tiktokanalytics_userconfigs
- Operations: Read
- Model:
external/models/analytics-tiktokanalytics-userconfig.js - Usage Context: Retrieve selected advertiser ID for all operations
🔄 Data Flow
sequenceDiagram
participant Client as DashClicks App
participant Controller as Analytics Controller
participant Keys as Keys Model
participant Provider as TikTok Provider
participant TikTok as TikTok Marketing API
Client->>Controller: GET /campaigns?limit=10&page=1
Controller->>Keys: Find token + advertiser config
Keys-->>Controller: Access token + advertiser_id
Controller->>Provider: getCampaignsList()
Provider->>TikTok: GET /campaign/get?advertiser_id=...
TikTok-->>Provider: Campaigns + page_info
Provider-->>Controller: Response data
Controller-->>Client: Campaigns with pagination
🔧 Campaign Management Functions
List Campaigns
campaigns(req, res, next)
Purpose: Retrieve paginated list of advertising campaigns for the configured advertiser account
Source: Controllers/analytics.js
External API Endpoint: GET https://business-api.tiktok.com/v1.3/campaign/get
Request:
GET /v1/integrations/tiktok/campaigns?limit=10&page=1&campaign_ids=123,456&status=CAMPAIGN_STATUS_ENABLE
Authorization: Bearer {jwt_token}
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | Number | ❌ | Results per page (becomes page_size in API) |
page | Number | ❌ | Page number (1-based, default: 1) |
campaign_ids | String | ❌ | Comma-separated campaign IDs to filter |
status | String | ❌ | Campaign status filter (e.g., CAMPAIGN_STATUS_ENABLE) |
Returns: Promise<Object>
Business Logic Flow:
-
Validate Account & Extract Config
- Call
checkAccountAccess(req)to get account ID - Fetch OAuth token via
keysModel.find(accountId) - Returns error if
KEYS_NOT_FOUND - Extract
advertiser_idfromexistKeys.configData
- Call
-
Build Query Parameters
- Set default
page = 1if not provided - If
limitprovided, addpage_size: limitto query params - Merge all request query parameters
- Add
advertiser_idfrom config
- Set default
-
Call TikTok Campaigns API
- Provider Function:
tiktokAnalyticsProvider.getCampaignsList() - HTTP Method: GET
- URL:
{TIKTOK_BASE_URL}/{TIKTOK_VERSION}/campaign/get - Headers:
Access-Token: {access_token} - Query Params:
{ advertiser_id, page_size, page, ...filters }
- Provider Function:
-
Generate Pagination Metadata
- Extract
total_numberfrom responsepage_info - Call
utilities.generatePagination(limit, page, totalRecords) - Returns pagination object with total pages, current page, etc.
- Extract
-
Return Response
- Campaign list from
campaignsList.data.list - Pagination metadata
- Campaign list from
API Request Example:
GET https://business-api.tiktok.com/v1.3/campaign/get?advertiser_id=1234567890&page_size=10&page=1
Headers:
Access-Token: act.1234567890abcdef...
API Response Example:
{
"code": 0,
"message": "OK",
"data": {
"list": [
{
"campaign_id": "123456",
"campaign_name": "Summer Sale Campaign",
"advertiser_id": "1234567890",
"objective_type": "TRAFFIC",
"status": "CAMPAIGN_STATUS_ENABLE",
"budget": 1000.00,
"budget_mode": "BUDGET_MODE_DAY",
"create_time": "2025-09-01 10:00:00",
"modify_time": "2025-10-01 15:30:00"
}
],
"page_info": {
"total_number": 45,
"page": 1,
"page_size": 10
}
}
}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": [
{
"campaign_id": "123456",
"campaign_name": "Summer Sale Campaign",
"advertiser_id": "1234567890",
"objective_type": "TRAFFIC",
"status": "CAMPAIGN_STATUS_ENABLE",
"budget": 1000.00,
"budget_mode": "BUDGET_MODE_DAY",
"create_time": "2025-09-01 10:00:00",
"modify_time": "2025-10-01 15:30:00"
}
],
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_records": 45,
"per_page": 10,
"has_next": true,
"has_prev": false
}
}
Error Handling:
- Returns 400 if account ID invalid
- Returns 400 if no OAuth token found (
KEYS_NOT_FOUND) - Passes TikTok API errors to Express error middleware
List Ad Groups
getAdGroups(req, res, next)
Purpose: Retrieve paginated list of ad groups for the configured advertiser account
Source: Controllers/analytics.js
External API Endpoint: GET https://business-api.tiktok.com/v1.3/adgroup/get
Request:
GET /v1/integrations/tiktok/adgroups?limit=20&page=1&campaign_id=123456
Authorization: Bearer {jwt_token}
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | Number | ❌ | Results per page (becomes page_size) |
page | Number | ❌ | Page number (1-based, default: 1) |
campaign_id | String | ❌ | Filter by campaign ID |
adgroup_ids | String | ❌ | Comma-separated adgroup IDs |
Business Logic: Same as campaigns, but calls getAdGroups() provider function
API Response Example:
{
"code": 0,
"message": "OK",
"data": {
"list": [
{
"adgroup_id": "7890123",
"adgroup_name": "Mobile Users 25-34",
"campaign_id": "123456",
"status": "ADGROUP_STATUS_ENABLE",
"budget": 500.00,
"bid_price": 1.50,
"optimization_goal": "CLICK",
"create_time": "2025-09-02 11:00:00"
}
],
"page_info": {
"total_number": 120,
"page": 1,
"page_size": 20
}
}
}
List Ads
getAds(req, res, next)
Purpose: Retrieve paginated list of individual ads for the configured advertiser account
Source: Controllers/analytics.js
External API Endpoint: GET https://business-api.tiktok.com/v1.3/ad/get
Request:
GET /v1/integrations/tiktok/ads?limit=50&page=1&adgroup_id=7890123
Authorization: Bearer {jwt_token}
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | Number | ❌ | Results per page (becomes page_size) |
page | Number | ❌ | Page number (1-based, default: 1) |
adgroup_id | String | ❌ | Filter by ad group ID |
ad_ids | String | ❌ | Comma-separated ad IDs |
Business Logic: Same as campaigns, but calls getAds() provider function
API Response Example:
{
"code": 0,
"message": "OK",
"data": {
"list": [
{
"ad_id": "456789",
"ad_name": "Video Ad - Product Launch",
"adgroup_id": "7890123",
"campaign_id": "123456",
"status": "AD_STATUS_ENABLE",
"create_time": "2025-09-03 09:00:00",
"modify_time": "2025-09-05 14:20:00",
"ad_text": "Check out our new product!",
"video_id": "v1234567890"
}
],
"page_info": {
"total_number": 350,
"page": 1,
"page_size": 50
}
}
}
📈 Integrated Analytics Reporting
Generate Analytics Report
reports(req, res, next)
Purpose: Generate comprehensive analytics reports with custom dimensions, metrics, and filtering at campaign, ad group, or ad level
Source: Controllers/analytics.js
External API Endpoint: GET https://business-api.tiktok.com/v1.3/report/integrated/get/
Request:
GET /v1/integrations/tiktok/reports?data_level=AUCTION_CAMPAIGN&start_date=2025-09-01&end_date=2025-10-10&metrics=["impressions","clicks","spend"]&dimensions=["campaign_id","stat_time_day"]&limit=100&page=1
Authorization: Bearer {jwt_token}
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
data_level | String | ✅ | Reporting level: AUCTION_CAMPAIGN, AUCTION_ADGROUP, AUCTION_AD |
start_date | String | ✅ | Start date (YYYY-MM-DD format) |
end_date | String | ✅ | End date (YYYY-MM-DD format) |
metrics | JSON Array | ✅ | Metrics to retrieve (e.g., ["impressions","clicks"]) |
dimensions | JSON Array | ✅ | Dimensions for grouping (e.g., ["campaign_id"]) |
limit | Number | ❌ | Results per page (becomes page_size) |
page | Number | ❌ | Page number (1-based, default: 1) |
campaign_ids | String | ❌ | Comma-separated campaign IDs to filter |
adgroup_ids | String | ❌ | Comma-separated adgroup IDs to filter |
ad_ids | String | ❌ | Comma-separated ad IDs to filter |
campaign_status | String | ❌ | Filter by campaign status |
adgroup_status | String | ❌ | Filter by adgroup status |
ad_status | String | ❌ | Filter by ad status |
search | String | ❌ | Search term for name filtering |
all_fields | Boolean | ❌ | Include all available metrics (see constants) |
Returns: Promise<Object>
Business Logic Flow:
-
Validate Account & Get Config
- Check account access and fetch OAuth token
- Extract
advertiser_idfrom config - Return error if not found
-
Handle
all_fieldsParameter- If
all_fields=true, push all available metrics from constants - Metrics defined in
constants/constants.js
- If
-
Status Filtering Logic (Complex Multi-Call Process)
For each data level, perform preliminary API calls to filter by status:
For
AUCTION_CAMPAIGNlevel:- Call
getCampaignsList()with:fields: ["campaign_id", "secondary_status", "budget"]filtering.secondary_status: Ifcampaign_statusprovidedfiltering.campaign_name: Ifsearchprovidedfiltering.campaign_ids: Ifcampaign_idsprovided
- Extract all matching
campaign_idvalues - Set filtered IDs in main query parameters
- Return empty array if no campaigns match filters
For
AUCTION_ADGROUPlevel:- Call
getAdGroups()with:fields: ["adgroup_id", "secondary_status", "schedule_infos", "budget", "bid_price"]filtering.secondary_status: Ifadgroup_statusprovidedfiltering.adgroup_name: Ifsearchprovidedfiltering.adgroup_ids: Ifadgroup_idsprovided
- Extract all matching
adgroup_idvalues - Set filtered IDs in main query parameters
- Return empty array if no adgroups match filters
For
AUCTION_ADlevel:- Call
getAds()with:fields: ["ad_id", "secondary_status"]filtering.secondary_status: Ifad_statusprovidedfiltering.ad_ids: Ifad_idsprovided
- Note: Ad name search not supported by TikTok API
- Extract all matching
ad_idvalues - Set filtered IDs in main query parameters
- Return empty array if no ads match filters
- Call
-
Build Filtering Array
- Convert ID filters to TikTok filtering format:
filtering: [
{
field_name: 'campaign_ids',
filter_type: 'IN',
filter_value: '[123,456,789]',
},
]; - Stringify filtering array for API
- Convert ID filters to TikTok filtering format:
-
Call Integrated Report API
- Provider Function:
tiktokAnalyticsProvider.getCreativereports() - HTTP Method: GET
- URL:
{TIKTOK_BASE_URL}/{TIKTOK_VERSION}/report/integrated/get/ - Headers:
Access-Token: {access_token},Content-Type: application/json - Query Params:
advertiser_iddata_levelstart_date,end_datemetrics(JSON stringified)dimensions(JSON stringified)filtering(JSON stringified)page_size(fromlimit)page
- Provider Function:
-
Merge Status Data into Report
- For each row in report
data.list: - Match by
campaign_id,adgroup_id, orad_id - Add extra fields from status API calls:
secondary_status- Current statusbudget- Budget amountschedule_infos- Schedule details (adgroups)bid_price- Bid price (adgroups)
- For each row in report
-
Generate Pagination
- Extract
page_info.total_numberfrom report response - Call
utilities.generatePagination(limit, page, total_number)
- Extract
-
Return Combined Response
- Report data with merged status fields
- Pagination metadata
API Request Example:
GET https://business-api.tiktok.com/v1.3/report/integrated/get/?advertiser_id=1234567890&data_level=AUCTION_CAMPAIGN&start_date=2025-09-01&end_date=2025-10-10&metrics=["impressions","clicks","spend","ctr","cpc"]&dimensions=["campaign_id","stat_time_day"]&page_size=100&page=1&filtering=[{"field_name":"campaign_ids","filter_type":"IN","filter_value":"[123456,789012]"}]
Headers:
Access-Token: act.1234567890abcdef...
Content-Type: application/json
API Response Example:
{
"code": 0,
"message": "OK",
"data": {
"list": [
{
"dimensions": {
"campaign_id": "123456",
"stat_time_day": "2025-09-01"
},
"metrics": {
"impressions": 45000,
"clicks": 1200,
"spend": 450.75,
"ctr": 2.67,
"cpc": 0.38,
// Merged from status API:
"secondary_status": "CAMPAIGN_STATUS_ENABLE",
"budget": 1000.00
}
},
{
"dimensions": {
"campaign_id": "123456",
"stat_time_day": "2025-09-02"
},
"metrics": {
"impressions": 52000,
"clicks": 1450,
"spend": 520.30,
"ctr": 2.79,
"cpc": 0.36,
"secondary_status": "CAMPAIGN_STATUS_ENABLE",
"budget": 1000.00
}
}
],
"page_info": {
"total_number": 300,
"page": 1,
"page_size": 100
}
}
}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": [
{
"dimensions": {
"campaign_id": "123456",
"stat_time_day": "2025-09-01"
},
"metrics": {
"impressions": 45000,
"clicks": 1200,
"spend": 450.75,
"ctr": 2.67,
"cpc": 0.38,
"secondary_status": "CAMPAIGN_STATUS_ENABLE",
"budget": 1000.00
}
}
],
"pagination": {
"current_page": 1,
"total_pages": 3,
"total_records": 300,
"per_page": 100,
"has_next": true,
"has_prev": false
}
}
Error Handling:
- Returns empty array if no matching campaigns/adgroups/ads found
- Logs errors during status filtering (non-fatal)
- Passes TikTok API errors to Express error middleware
Side Effects:
- ⚠️ Makes multiple API calls for status filtering
- ⚠️ Can consume significant API quota for large reports
- ⚠️ Merges data from multiple API responses
🎯 Available Metrics & Dimensions
Popular Metrics:
| Metric | Description |
|---|---|
impressions | Number of times ads were shown |
clicks | Number of ad clicks |
spend | Total ad spend in account currency |
ctr | Click-through rate (clicks/impressions) |
cpc | Cost per click (spend/clicks) |
conversion | Total conversions |
cost_per_conversion | Average cost per conversion |
video_play_actions | Video play count |
video_watched_2s | Videos watched for 2+ seconds |
video_watched_6s | Videos watched for 6+ seconds |
reach | Unique users reached |
frequency | Average impressions per user |
Popular Dimensions:
| Dimension | Description |
|---|---|
campaign_id | Campaign identifier |
campaign_name | Campaign name |
adgroup_id | Ad group identifier |
adgroup_name | Ad group name |
ad_id | Individual ad identifier |
ad_name | Ad name |
stat_time_day | Date (YYYY-MM-DD format) |
stat_time_hour | Hour breakdown |
All Available Fields: See constants/constants.js allFields array for complete list
🔀 Data Levels
TikTok supports three reporting levels:
AUCTION_CAMPAIGN
- Use Case: Campaign performance overview
- Dimensions Available: Campaign ID, name, date/time
- Best For: High-level budget and performance tracking
AUCTION_ADGROUP
- Use Case: Ad group performance and targeting analysis
- Dimensions Available: Campaign + ad group info, targeting details
- Best For: Audience and placement performance
AUCTION_AD
- Use Case: Individual ad creative performance
- Dimensions Available: Campaign + adgroup + ad info
- Best For: Creative optimization and A/B testing
⚠️ Important Notes
- 🔐 Advertiser Required: All operations require saved advertiser config
- 📊 Multiple API Calls: Reporting with status filters makes 2-3 API calls
- 🎯 Status Filtering: Separate API calls needed for status-based filtering
- 📅 Date Range: Reports support custom date ranges
- 💰 Currency: All spend values in advertiser account currency
- ⏱️ Timezone: All timestamps in advertiser account timezone
- 📈 Pagination: Large reports automatically paginated
- 🔄 Status Merging: Report data merged with real-time status info
- ⚡ Rate Limits: High-volume reports may hit rate limits
- 🚫 Search Limitations: Ad name search not supported by TikTok API
🔗 Related Documentation
- Integration Overview: TikTok Integration Index
- Authentication: OAuth 2.0 Flow
- Accounts: Advertiser Management
- TikTok Reporting API: Integrated Reports Documentation
- TikTok Campaign API: Campaign Management