Architecture · Draft
First-Party Tag Relay (Kobico Relay) — Phase 2+
Status: Deferred — not v1 scope. v1 uses API-provisioned pixels/CAPI plus implementation guide. This doc captures the recommended later architecture, cloud choice, and cost bands for planning.
Problem
| Issue | v1 approach | Relay approach (later) |
|---|---|---|
| Third-party cookie limits | CAPI + manual/GTM guide | First-party subdomain cookies |
| Client installs many pixels | Per-platform guide | One DNS + one script |
| Ad blockers | Platform domains blocked | Requests to metrics.client.com |
| Ops at scale | Per-tenant GTM publish | Kobico-operated fan-out |
Client effort (target)
| Step | Who | Once per tenant? |
|---|---|---|
CNAME metrics.{client-domain} → Kobico edge |
Client DNS | Yes (first-party default) |
| One loader snippet (or GTM import that loads it) | Client site / CMS | Yes |
| Consent banner — Kobico CMP included | Client approves copy + privacy policy URL in portal | Yes for EEA/UK/TR — see Consent management |
Not required: Separate CMP purchase before onboarding, Meta pixel, TikTok pixel, separate GTM publish per platform, client payment to a CMP vendor.
Loader delivery modes
| Mode | Script URL | When |
|---|---|---|
| First-party (default) | https://metrics.{client-domain}/k.js?tenant_id=… |
All production Relay SKUs — best cookies, blockers, Consent Mode |
| Third-party (opt-in) | https://tracking.kobi.com/k.js?tenant_id=… |
Client cannot set DNS yet, pilot, or explicit choice — portal labels “reduced tracking mode” |
Same manifest, modules, and relay backend for both modes. Third-party mode uses stricter QC — do not mark tracking green on parity with first-party without review.
Locked in ADR 0005.
Architecture options
A — Kobico Relay (preferred product path)
- Browser: thin loader collects page context, click IDs, consent,
event_id - Edge: TLS for client hostname, rate limit, WAF
- Relay: normalize vertical templates, dedup, hash PII, fan-out (same APIs as v1 CAPI relay)
B — Hosted server-side GTM (alternative SKU)
Same CNAME; origin runs GTM server container instead of custom relay. Industry-standard; heavier to automate multi-tenant.
| Kobico Relay (A) | Hosted sGTM (B) | |
|---|---|---|
| Client install | CNAME + one script | CNAME + GTM web snippet |
| Kobico maintains | Code + templates | GTM container versions |
| Agent/QC integration | Native | Indirect |
| Google ecosystem | Via MP / EC APIs | Native GTM tags |
Recommendation: Build A as default SKU; offer B only for GTM-mature clients.
k.js micro-module architecture
Locked: ADR 0005 — Pattern A bootstrap + cached chunks; hybrid Cloudflare edge + GCP Cloud Run origin.
Runtime flow
Module taxonomy
| Layer | Size target | Responsibility | Repo path (illustrative) |
|---|---|---|---|
k.js bootstrap |
≤1 KB gz | Read tenant_id, fetch manifest |
src/bootstrap/ |
k-core.js |
≤3 KB gz | Click IDs (gclid, fbclid, ttclid), Consent Mode v2, cookie policy, relay POST, event_id, window.kobiConsent bridge |
src/core/ |
| Global listeners | Per module | Stable platform APIs — Shopify, WooCommerce, generic dataLayer |
src/listeners/global/ |
| Local listeners | Per module | Regional e-commerce DOM integrations — ikas, Ticimax, IdeaSoft | src/listeners/local/ |
Rules: Local listeners depend only on k-core public API — no cross-imports between listeners. Each module ships as an immutable versioned URL with long edge cache. Marketing modules load only after marketing consent; analytics modules after analytics consent.
Tenant manifest (edge)
Resolved at onboarding and stored in edge KV/D1; referenced by bootstrap:
| Field | Example | Purpose |
|---|---|---|
tenant_id |
uuid | Identity |
delivery_mode |
first_party |
CNAME vs third-party loader |
vertical |
ecommerce_tr |
Event schema / templates |
platform |
ikas |
Primary local listener key |
global_hooks |
["woocommerce"] |
Optional extra global listeners |
enabled_modules |
["core","listener-ikas","ga4"] |
Edge-resolved load list |
consent_profile |
tr_kvkk |
Legal strictness |
cmp_mode |
kobi_cmp |
See Consent management |
platform selects the primary regional adapter; vertical drives event names. Edge derives enabled_modules from plan SKU + platform + vertical — onboarding does not hand-pick ten flags.
Delivery pattern — Pattern A (default)
- Browser loads
k.js(bootstrap). - Bootstrap fetches manifest from edge (short TTL / ETag).
- Loads
k-core.js(static, globally cached). - Resolves consent (Kobico CMP default or external CMP bridge).
- Lazy-loads optional modules (
listener-global-shopify.js,listener-local-ikas.js, …). - Relay POST — first-party: same-origin on
metrics.client.com; third-party: configured relay endpoint.
Not used for MVP: edge-stitched single file per tenant (Pattern B) or per-tenant CI bundles (Pattern C).
Phased module rollout
Relay ships incrementally — clients need not wait for every platform adapter:
| Sub-phase | Delivers | Client experience |
|---|---|---|
| 2a | k-core + relay + Kobico CMP | CNAME + one script; CAPI fan-out; implementation pack still useful for gaps |
| 2b | Global listeners | Shopify / WooCommerce auto events |
| 2c | Local listeners | ikas, Ticimax, IdeaSoft |
| 2d | Bundled / partner CMP options | See Global CMP partnerships |
Performance and cost budgets (planning)
| Metric | Target |
|---|---|
| k-core gzipped | ≤ 3 KB |
| Typical extra modules after consent | ≤ 2–3 cached chunks |
| Total JS before consent | Bootstrap + k-core only |
| Manifest fetch | Edge KV — no GCP round-trip |
| Relay POST | Cloud Run — same fan-out as v1 CTS |
Protects client PageSpeed / SEO and keeps edge transfer bounded at Growth scale (~50 tenants, ~10M req/mo — see Cost estimation).
API / scope compatibility
Relay fan-out uses the same endpoints as v1 — no special “server-side tagging scope”:
| Destination | API | Already in onboarding? |
|---|---|---|
| Meta | Conversions API (/{pixel-id}/events) |
✅ Pixel + system user token |
| TikTok | Events API (/event/track/) |
✅ Pixel + OAuth |
| GA4 | Measurement Protocol | ✅ If client grants Admin / measurement ID |
| Google Ads | Enhanced Conversions / offline upload | ✅ Conversion actions |
| Internal CRM | Webhook / CTS | ✅ Phase 4 |
GTM Tag Manager API is only needed for option B (container publish) — not for Kobico Relay.
Consent management — required for Relay
Yes. If Kobico Relay sets first-party cookies and fans out events to Meta, TikTok, GA4, and Google Ads, consent must be enforced before non-essential processing. A DNS record and loader alone do not satisfy GDPR, UK GDPR, or KVKK — the relay becomes part of the client’s tracking stack and must respect visitor choice.
This is separate from portal consents (ToS, data-sharing, Meta OAuth) in onboarding provisioning spec §7. Relay needs website visitor cookie consent in addition.
Responsibility split
| Party | Role |
|---|---|
| Client | Privacy policy, lawful basis, banner copy approval, DPA with Kobico — per vision & scope |
| Kobico | Implement consent gating in k.js + relay; Consent Mode v2; block fan-out when denied; audit-friendly logs |
| End user | Accept / reject / customize via banner or existing CMP |
Relay must not treat server-side fan-out as a loophole: if marketing consent is denied in the browser, the relay drops or anonymizes ad-personalization payloads (CAPI with restricted parameters, no new marketing cookies).
Consent categories (default taxonomy)
| Category | Examples | Default (EEA/UK) | Fan-out when denied |
|---|---|---|---|
| Necessary | Relay session, security, consent storage | Always on | N/A — no ad platforms |
| Analytics | GA4 page views, key events | Opt-in | Skip GA4 MP; optional aggregate internal metrics only |
| Marketing | Meta CAPI, TikTok Events API, Google Ads EC, remarketing cookies | Opt-in | Block platform fan-out; no _fbp / ad cookies |
Tenant config: consent_profile on tenant_registry — eea_strict | uk_strict | tr_kvkk | row_light (still document; no silent opt-in where law requires opt-in).
CMP deployment modes (pick per tenant at onboarding)
| Mode | Client has | Kobico delivers | Default? |
|---|---|---|---|
| 2 — Kobico CMP | Nothing required | Included banner with k.js — TR + EN MVP; client approves copy in portal |
Yes — Relay SKU default |
| 1 — Client CMP | Cookiebot, OneTrust, iubenda, CookieYes, etc. | k.js listens to CMP API / dataLayer / TCF __tcfapi |
When client already runs a CMP |
| 4 — Kobico-bundled CMP | Legal/compliance prefers named vendor | Kobico holds portfolio license; no separate client CMP invoice — cost in Relay bundle | When partnership or resell active |
| 3 — GTM hybrid | GTM shop | GTM import: CMP first, then k.js on consent update |
Agency clients |
Product rule: Onboarding must not require “purchase a CMP elsewhere, then return.” Default path is Mode 2 (Kobico CMP included). Modes 1 and 4 are opt-in via portal Consent provider selector.
Default recommendation: cmp_mode = kobi_cmp at Relay enablement. Mode 1 when client BYO CMP is detected or selected. Mode 4 when leadership closes a bundled global CMP offer (partnerships).
Consent banner game plan (implementation)
Phase A — Tenant config (onboarding Relay SKU)
| Field | Purpose |
|---|---|
delivery_mode |
first_party | third_party |
consent_profile |
eea_strict / uk_strict / tr_kvkk / row_light |
cmp_mode |
kobi_cmp (default) | client_cmp | kobi_bundled_cmp | gtm_hybrid |
cmp_vendor |
kobi | cookiebot | onetrust | iubenda | … |
platform |
Primary local listener — ikas, ticimax, ideasoft, … |
vertical |
Event schema — tourism, ecommerce_tr, … |
privacy_policy_url |
Required — linked from banner |
banner_locale |
tr, en, de, … |
google_consent_mode |
v2 enabled (default true for EEA/UK) |
Store website consent config on onboarding_record.tracking_relay; link to portal consent_record for contractual data-sharing — two layers, one audit trail.
Phase B — Loader (k.js) behavior
- Default denied for analytics + marketing in EEA/UK until CMP fires
consent_update. - Expose
window.kobiConsentbridge for client CMP integrations. - Set Google Consent Mode v2 defaults (
ad_storage,analytics_storage,ad_user_data,ad_personalization) before any hit. - Set first-party cookies only when category allows (e.g.
_fbponly if marketing granted). - Queue events in memory until consent known; flush or purge on deny.
- Attach
consent_snapshot(categories + CMP version + timestamp) on each relay POST — relay logs, does not re-interpret legal text.
Phase C — Relay server gates
| Check | Action if fail |
|---|---|
consent.marketing !== true |
Drop Meta / TikTok / Ads fan-out; return 204 |
consent.analytics !== true |
Drop GA4 MP |
Missing consent_snapshot on EEA tenant |
Treat as denied (strict) |
| Event contains PII + marketing denied | Strip / hash per data & tracking privacy rules |
Optional: persist anonymized consent metrics to BigQuery (relay_consent_events) for ops — not a substitute for CMP records.
Phase D — Platform-specific signals
| Platform | Relay behavior |
|---|---|
Consent Mode v2 in loader; Enhanced Conversions only if ad_user_data granted |
|
| Meta | CAPI data_processing_options / LDU where required; no pixel-equivalent cookies without marketing consent |
| TikTok | Events API with consent flags per TikTok docs for region |
| GA4 | MP with consent-aware parameters; respect analytics_storage |
Pin exact parameter names at implementation — platform docs change; QC checker validates consent fields present for EEA tenants.
Phase E — Client CMP integration cookbook (Mode 1)
Document in implementation guide v2 — one snippet per major CMP:
| CMP | Integration hook |
|---|---|
| Cookiebot | Cookiebot.consent + CookieConsent event |
| OneTrust | OnetrustActiveGroups + OneTrustGroupsUpdated |
| iubenda | _iub.cs.api |
| TCF v2 | __tcfapi('getTCData') → map purposes to analytics/marketing |
Kobico maintains a compatibility matrix; unknown CMP → default Kobico CMP or HITL onboarding step — never block Relay on external CMP procurement.
Global CMP partnerships and bundled resell
Partnership program (active — discuss with leadership / board): Pursue formal partnerships with global CMP vendors (Cookiebot, OneTrust, iubenda, CookieYes, and peers) for portfolio pricing, co-marketing, TR/EU localization, and support escalation. Partnership is on the table alongside Kobico CMP — not instead of it.
| Track | Kobico action | Client sees |
|---|---|---|
| Kobico CMP (default) | Build + operate banner on metrics.client.com |
Consent included in Relay SKU |
| Partnership CMP | Signed reseller/OEM agreement with vendor | Same — included; vendor named in subprocessor list |
| Bundled resell (interim) | Kobico subscribes at portfolio level until partnership closes | No separate CMP checkout — cost absorbed in media-tech / Relay bundle |
| Client BYO | Integration only (client_cmp) |
Client keeps existing contract |
If a vendor declines partnership, Kobico may still bundle that CMP at no incremental client charge (Pattern: portfolio seat allocation) rather than sending clients to procure consent tooling separately. Model fully loaded CMP cost (~€2–8/site/mo at SMB tiers) into existing €5–15/site/mo Relay planning band.
Exec checklist (partnerships): target vendor list, DPA/subprocessor terms, white-label vs co-brand, TCF registration responsibilities, TR locale coverage, rev-share vs flat portfolio fee.
Phase F — Kobico CMP (Mode 2) MVP scope
| In scope | Out of scope (v2 Relay MVP) |
|---|---|
| TR + EN banner strings (legal review) | Full IAB TCF registration as CMP |
| Accept all / reject non-essential / customize (3 categories) | Geo-IP auto-law detection (use tenant consent_profile first) |
Consent cookie on metrics.client.com or registrable domain |
Replacing enterprise CMP for Fortune 500 clients |
| Re-open preferences link in implementation guide footer snippet |
Banner UI: small bundle served from same subdomain as k.js; theme tokens from tenant brand colors.
Phase G — Ops, QC, and HITL
| Signal | Threshold | Action |
|---|---|---|
| EEA tenant with zero consent grants but high event volume | Any | Block relay — config bug; System Ops alert |
| Consent grant rate unusually low | < 5% over 7d | Notify client — banner placement/copy |
| Relay fan-out without snapshot (EEA) | > 0 | QC fail; do not mark tracking healthy |
| Client changes privacy policy URL | — | Re-acknowledge in portal (lightweight) |
Add ONB-14 (future): Relay enabled but privacy_policy_url or consent_profile missing → block tracking_relay.active.
Consent + engineering cost add-on
| Workstream | Duration | Notes |
|---|---|---|
| Consent gating in loader + relay | +1.5 weeks | Included in Relay MVP row — now explicit |
| Client CMP integration matrix | +1 week | Top 4 CMPs + TCF stub |
| Kobico CMP (default, Mode 2) | +1.5–2 weeks | UI + locales + legal copy templates |
| Global CMP partnership / bundle ops | Ongoing (exec) | Portfolio licensing; not blocking 2a |
| Consent health dashboard | +0.5 week | Overlap with relay health row |
Infra: Kobico CMP adds negligible cost (static assets on same edge as k.js). Third-party CMP seats absorbed in bundle when cmp_mode = kobi_bundled_cmp — see Global CMP partnerships.
Cloud provider recommendation
Default: GCP for compute + Cloudflare for edge (hybrid).
| Layer | Service | Why |
|---|---|---|
Static assets (k.js, k-core, modules) |
Cloudflare CDN | Global cache; immutable versioned URLs |
| Tenant manifest | Cloudflare Workers + KV/D1 | Sub-ms manifest; no GCP hop for loader |
| Multi-tenant custom hostnames | Cloudflare (SSL for SaaS / proxied CNAME) | Cheap per-client TLS at 50–200+ tenants; global edge; DDoS; WAF |
| Relay logic | GCP Cloud Run | Same as orchestrator, connectors, CTS, Secret Manager, logging → BQ — one IAM and ops model (GCP topology) |
| Certificates (pilot only) | GCP Certificate Manager + Global HTTPS LB | OK for <15 tenants all-GCP pilot — fewer vendors |
| Secrets / tokens | GCP Secret Manager | Pixel tokens already planned here |
| Telemetry | Cloud Logging → BigQuery | Aligns with System Ops + QC |
Why not AWS / Azure as primary?
- Rest of Kobico Digital Ads is GCP-illustrative (Vertex, Cloud Run, BQ).
- Splitting relay to Lambda@Edge or Azure Front Door adds second billing, IAM, and runbooks for marginal savings at pilot scale.
- Revisit only if entire Kobico platform standardizes elsewhere.
Why not Workers-only (no GCP)?
- Cloudflare Workers can host the full relay (very cost-effective).
- Downside: platform tokens, CTS, and tenant registry live on GCP — cross-cloud latency, dual deploy, harder trace from ad event → agent QC.
- Compromise: Cloudflare edge (SSL, cache, WAF) → GCP Cloud Run origin — best performance/cost/ops balance.
Region
- Relay origin:
europe-west1(match GCP topology) unless tenant data residency requires otherwise. - Cloudflare: automatic anycast edge (client-facing latency minimized globally).
Cost estimation
Planning bands only. Verify against Cloud Run, Cloud Load Balancing, Cloudflare plans, and Certificate Manager before build. Prices USD, order-of-magnitude, relay infra only (excludes Vertex, ads APIs, ERP).
Traffic assumptions
| Profile | Tenants | Page views / tenant / month | Relay requests / tenant / month¹ |
|---|---|---|---|
| Pilot | 5 | 25,000 | ~100,000 |
| Growth | 50 | 50,000 | ~200,000 |
| Scale | 200 | 100,000 | ~400,000 |
¹ Loader load + page/events + retries. Fan-out to Meta/TikTok/GA4 is outbound from Cloud Run (small payloads; egress cost negligible vs ingress).
Monthly infrastructure (USD)
| Profile | Total requests/mo | Hybrid (CF + GCP Run) | All-GCP (LB + Run + certs) |
|---|---|---|---|
| Pilot (5 tenants) | ~0.5M | $25–45 | $40–70 |
| Growth (50 tenants) | ~10M | $80–150 | $180–320 |
| Scale (200 tenants) | ~80M | $350–650 | $900–1,600 |
Hybrid breakdown (Growth example, ~10M requests/mo):
| Line item | Est. monthly |
|---|---|
| Cloud Run (relay + fan-out CPU) | $35–70 |
| Cloudflare Pro/Business + custom hostnames (~50) | $25–55 |
| GCP logging / BQ relay telemetry (light) | $10–25 |
| Secret Manager, Pub/Sub (optional async buffer) | $5–15 |
| Total | ~$80–150 |
All-GCP premium drivers: Global HTTPS LB (~$18+ base + LCU), Certificate Manager per hostname, no edge cache for k.js unless Cloud CDN added.
Marginal cost per tenant (steady state, hybrid)
| Tenant traffic | Est. infra / tenant / month |
|---|---|
| Low (25k page views) | $1–3 |
| Medium (50k page views) | $2–5 |
| High (200k page views) | $6–12 |
Pass-through pricing to clients (optional SKU): media-tech fee €5–15 / site / month easily covers infra at Growth scale.
One-time engineering (build)
| Workstream | Duration | Notes |
|---|---|---|
| Relay service (ingest, dedup, fan-out) | 4–5 weeks | Cloud Run, vertical templates |
| k-core + bootstrap (Pattern A) | 2 weeks | Manifest service, edge routing |
| Consent (Kobico CMP default + client CMP matrix) | 2–3 weeks | See Consent management |
| Edge onboarding (CNAME verify, TLS, tenant routing) | 2 weeks | Cloudflare for SaaS |
| Global + local listeners (phased 2b/2c) | 2–4 weeks | After 2a pilot — per platform |
| Dashboard health (volume, EMQ proxy, consent) | 1 week | Ties to data & tracking |
| Hosted sGTM path (optional B) | +2 weeks | Only if product requires |
| Total MVP (2a — core + relay + Kobico CMP) | ~10–12 weeks | 1–2 engineers; 2b/2c additive |
Opportunity cost vs v1 guide: v1 avoids this build; relay pays off at ~20+ active sites or when client IT friction dominates onboarding SLA.
Multi-tenant design notes
| Concern | Approach |
|---|---|
| Host routing | Host: metrics.client.com → tenant_id in registry |
| Third-party loader | Shared hostname tracking.kobi.com — opt-in only |
| Isolation | Per-tenant rate limits; no cross-tenant tokens in memory |
k.js delivery |
Pattern A — bootstrap + cached k-core + lazy modules |
| Manifest | Edge KV/D1 — vertical, platform, enabled_modules |
| Consent | Kobico CMP default; client/partner CMP via bridge — Consent management |
| Dedup | Browser event_id + server id → Meta/TikTok requirements |
| Domain verify (platform) | Still separate from CNAME — onboarding |
Phasing
| Phase | Tracking delivery |
|---|---|
| v1 | API pixels + CAPI + implementation guide (manual / GTM import template) |
| v2a | Relay core — CNAME (or third-party opt-in) + k-core + Kobico CMP + server fan-out |
| v2b | + Global listeners (Shopify, WooCommerce) |
| v2c | + Local listeners (ikas, Ticimax, IdeaSoft) |
| v2d | + Bundled / partner global CMP options |
| v2+ alt | Hosted sGTM for GTM-native clients |
See Roadmap — Phase 2+ optional.
Related documents
- ADR 0005: k.js relay micro-modules & CMP product
- Data & tracking
- GCP deployment topology
- Onboarding provisioning spec
- Platform access & API readiness
- Security & governance — GDPR / KVKK
- GA4 source of truth — Consent Mode v2 sign-off