[source-tiktok-marketing] Website and Shop conversion metrics missing, and conversion metrics unavailable at campaign level
- Langage dominant
- Python
- Étoiles
- 22.1k
- Forks
- 5.3k
- Métriques de merge des PR
- Métriques de PR en attente
Description
### Connector Name
source-tiktok-marketing
### Connector Version
5.1.11
### What step the error happened?
None
### Relevant information
**Summary.** Four observable problems with the basic report streams, in order of severity:
- **A. Adds to cart silently reports `0`.** The connector requests only the App leg of this
metric. For an advertiser with no MMP-connected app that leg is legitimately `0`, so the
column renders as a hard zero rather than as missing data — indistinguishable from a
campaign that genuinely drove no carts. On the account we measured the true figure is
**10,464**. *(detail in §1)*
- **B. Content views cannot be produced at all.** None of its three channel legs is
requested on any stream. True figure on the same account: **134,006**. *(§1)*
- **C. No conversion metric beyond app installs exists at campaign level.** 48 metrics the
connector already requests are scoped to lower-level streams. Since `reach` exists *only*
at campaign level, no campaign report can combine reach with conversions. *(§2)*
- **D. `campaigns_reports_daily` advertises metrics it never returns.** Its declared schema
is the shared `base_report_daily` superset, so the Airbyte UI shows `complete_payment`,
`total_pageview` and others as available fields; they arrive absent. *(§3)*
Details and measurements below. The root cause of A and B is that TikTok splits every
conversion event across three channels, and we have not been able to find any cross-channel
roll-up metric in the Reporting API. The three channels are:
| Channel | Source | Adds to cart | Content views | Purchases |
|---|---|---|---|---|
| **Website** | TikTok Pixel | `web_event_add_to_cart` | `page_content_view_events` | `complete_payment` |
| **App** | MMP / SDK | `total_app_event_add_to_cart` | `total_view_content` | `total_purchase` |
| **Shop** | TikTok Shop | `onsite_on_web_cart` | `onsite_on_web_detail` | `onsite_shopping` |
To report a single "adds to cart" or "content views" figure the way TikTok Ads Manager does,
all three legs have to be requested and summed. They appear to be disjoint measurement
surfaces — one order cannot be an in-app MMP purchase *and* a web pixel purchase *and* a
TikTok Shop order — so summing should not double-count.
**Of those nine metrics the connector requests only three**, and never above ad level:
| Funnel step | Website | App | Shop | Net effect |
|---|:--:|:--:|:--:|---|
| adds to cart | ❌ | ✅ ad level | ❌ | reads `0` for any advertiser without an MMP-connected app |
| content views | ❌ | ❌ | ❌ | **cannot be computed at all** |
| purchases | ✅ ad level | ❌ | ✅ ad level | ad level only; understated for app purchases |
That is problems A and B above. Purchases is the one funnel step that works, and only at ad
level.
**This request covers all three channels (Website / App / Shop) across all three entity
levels (campaign / ad group / ad).**
#### 1. Please add these 7 metrics — currently missing from every stream
**The ask: add the following 7 metrics to the basic report streams.** Verified by parsing
`manifest.yaml`: the union of the shared 27-metric base list plus every per-stream
`report_metrics` block is 87 metrics, and none of these appears in it — so no combination of
enabled streams can return them. **All 7 are confirmed valid and populated** by calling the
Reporting API directly (evidence below).
| Metric | TikTok display name | Channel | Funnel step |
|---|---|---|---|
| `web_event_add_to_cart` | Adds to cart (website) | **Website** | adds to cart |
| `onsite_on_web_cart` | Add to cart (Shop) | **Shop** | adds to cart |
| `page_content_view_events` | Content views (page) | **Website** | content views |
| `onsite_on_web_detail` | Product page views (Shop) | **Shop** | content views |
| `total_view_content` | Content views (app) | **App** | content views |
| `total_purchase` | Purchases (app) | **App** | purchases |
| `total_sales_lead_value` | Lead generation value (app) | **App** | conversion value |
> **On the total- vs unique-basis variants.** The connector does request `purchase`, but
> that is the *unique* app-purchase count, which TikTok documents as non-additive — it
> cannot be summed with the Website and Shop legs. The additive counterpart `total_purchase`
> is the one missing. Same distinction for content views: the connector has neither
> `view_content` (unique) nor `total_view_content` (total). For adds to cart the connector
> already has the correct total-basis field, `total_app_event_add_to_cart`.
> **On `page_content_view_events` vs the deprecated `product_details_page_browse`.** These
> are the same event, so only one is needed. We confirmed it: over the full account history
> (2022-07-05 → 2026-09-10) at campaign level both return **exactly 134,178**. TikTok marks
> `product_details_page_browse` deprecated and the Ads Manager glossary lists the
> "Content views (page)" family, so we are asking only for `page_content_view_events`. If
> you would rather ship the deprecated one for continuity, that works equally well — but
> they must never both be summed.
#### Evidence: we tested this against the Reporting API
Because TikTok's supported-metrics page is JavaScript-rendered and cannot be read
programmatically, we tested `/open_api/v1.3/report/integrated/get/` directly against a live
advertiser on 2026-09-10. Findings:
1. **Every numeric metric is valid at every `data_level`** — `AUCTION_AD`, `AUCTION_ADGROUP`,
`AUCTION_CAMPAIGN` *and* `AUCTION_ADVERTISER`, and also with the `country_code` dimension.
The connector's current per-level omissions are not API restrictions.
2. **Only entity descriptors are level-scoped**, as you would expect: `ad_name`/`ad_text` at
ad level only; `adgroup_name`, `placement_type`, `promotion_type`,
`dpa_target_audience_type`, `mobile_app_id`, `tt_app_id`, `tt_app_name` at ad and ad-group
level; `campaign_name` everywhere except advertiser level.
3. **`report_type=AUDIENCE` rejects all of these metrics** (`spend` is accepted, they are
not). The audience streams use a separate retriever, so they must be left as they are.
4. **Adding the metrics does not perturb existing ones.** We ran each stream's exact current
metric list against the same list plus the additions, over a 30-day window, and compared
row by row: **0 value differences** across 27 existing metrics at campaign level, 50 at ad
group and 85 at ad — with identical row keys.
5. **The new values are correct.** Row-by-row against an independent extract of the same
account for the same window: 0 mismatches at campaign and ad-group level on every metric
tested, including `spend` and `impressions` as controls.
6. A request must contain at least one *numeric* metric — a descriptor alone returns 40002.
Duplicate metric names in one request are accepted.
#### 2. Please also expose the existing ad-level metrics at campaign and ad group level
A second, separate request. Beyond the metrics missing everywhere, a large set the connector
**already requests** is scoped to the lower-level streams. Metric-key counts per stream:
**campaign 28, ad group 51, ad 87**.
At campaign level the only conversion metrics available are the three app-install ones
(`app_install`, `real_time_app_install`, `real_time_app_install_cost`). Every other
conversion metric the connector supports — web, Shop, purchase, registration, lead, and the
generic `conversion` / `result` families — is absent from `campaigns_reports_daily`.
**33 metrics exist only on the ad-level streams** (absent from both ad group and campaign):
```
complete_payment total_complete_payment_rate value_per_complete_payment
purchase purchase_rate total_purchase_value
cost_per_purchase onsite_shopping total_onsite_shopping_value
total_app_event_add_to_cart cost_per_total_app_event_add_to_cart
registration registration_rate cost_per_registration
sales_lead sales_lead_rate cost_per_sales_lead
cost_per_total_sales_lead total_pageview profile_visits_rate
cta_conversion cta_purchase vta_conversion
vta_purchase engagements engaged_view
engaged_view_15s engaged_view_through_conversions
paid_engaged_view paid_engaged_view_15s
paid_engagement_engaged_view paid_engagement_engaged_view_15s
cost_per_app_install
```
**15 more exist at ad and ad group level but not campaign:**
```
conversion conversion_rate cost_per_conversion
real_time_conversion real_time_conversion_rate real_time_cost_per_conversion
result result_rate cost_per_result
real_time_result real_time_result_rate real_time_cost_per_result
secondary_goal_result secondary_goal_result_rate cost_per_secondary_goal_result
```
**Why this is needed rather than just aggregating from ad level.**
We verified against the live API (full history, `include_deleted` on) that ad-level rows
**do** aggregate up to the campaign figures exactly — spend, impressions, `conversion`,
`complete_payment`, `web_event_add_to_cart`, `page_content_view_events` and
`total_complete_payment_rate` all reconcile to **0.00%**. So for those metrics, rollup is a
faithful workaround.
**`reach` is the exception, and it is what makes this a blocker.** Reach is deduplicated per
level, so summing ads double-counts anyone reached by more than one ad: over the same full
history, ad-level reach sums to 4,528,358 against a campaign-level 2,966,554 — a **52.65%
overstatement**. Reach can only ever come from the campaign stream.
That is the bind: **reach is available only at campaign level, and every conversion metric is
available only below it.** A campaign report combining reach with conversions cannot be built
from any combination of streams today — not because the numbers cannot be reconciled, but
because the two facts are never present at the same level. Adding the metrics at campaign
level resolves it directly, and also removes the need for rollup logic in every downstream
model.
**Concretely, to make every level usable** — all verified valid at the level shown:
| Stream | Metrics today | Add |
|---|---|---|
| `ads_reports_daily` | 87 | **7** (the funnel legs in §1) |
| `ad_groups_reports_daily` | 51 | **13** (the §1 legs + `complete_payment`, `onsite_shopping`, `total_app_event_add_to_cart`, `total_complete_payment_rate`, `total_onsite_shopping_value`, `total_purchase_value`) |
| `campaigns_reports_daily` | 28 | **17** (the ad-group set + `conversion`, `conversion_rate`, `cost_per_conversion`, `real_time_conversion`) |
#### 3. Note on the declared schema
`campaigns_reports_daily` advertises metrics it never returns. It does
`$ref: "#/definitions/base_report_daily"`, and that shared schema declares the full superset
of metric properties (`total_pageview`, `total_app_event_add_to_cart`, `complete_payment`, …)
while the stream's own `report_metrics` parameter is just `["campaign_name"]`. Users
inspecting the schema in the UI reasonably conclude these fields are available; they arrive
absent. Narrowing the per-stream schemas, or documenting the difference, would avoid this.
### Why this matters
Without the Website and Shop legs, the connector cannot reproduce TikTok Ads Manager's own
funnel figures — content views cannot be produced at all, and adds to cart silently reports
zero for advertisers with no connected app. Combined with the level asymmetry, campaign-level
conversion reporting is impossible: reach exists only at campaign level and conversions only
below it, so the two can never be combined. None of this is a TikTok API
limitation: another pipeline reading the same Reporting API returns all three channels at all
three levels for this same advertiser. The data is available — the connector simply does not
request it. This is currently blocking our move onto Airbyte for TikTok.
### Relevant log output
```shell
N/A — this is a missing-capability report, not a runtime error. The connector syncs
successfully; the metrics are simply never requested.
```
### Contribute
- [x] Yes, I want to contribute
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.