Adset.ProAdset.ProKnowledge base
Home/Training Materials/How Traffic Routing Works in Campaigns

How Traffic Routing Works in Campaigns

What is routing and why is it needed

Routing is a mechanism that determines what to show to each specific user who clicks on a tracking link.

Business tasks of routing:

  • Geo-distribution: if you are pouring from FB to EU and LATAM — need to send European traffic to the offer 1win, and LATAM — to mostbet

  • A/B testing: two creatives or two PWA designs — need a 50/50 split and Sticky Flow so that one user does not see both options

  • Protection from moderation: FB/Instagram moderators click on ads — they need to be sent to a harmless White Page

  • Device optimization: Android → PWA with installation, iOS → separate funnel (or external PWA / iOS App)

  • Bot filtering: cut off bots and proxies before passing click_id to the partner

Example: You launch a campaign from FB. You created two Stream Sets: the first one — for mobile Android traffic from target GEO (PWA + offer 1win), the second — for desktop (landing + offer parimatch). Everything else (bots, moderators, non-target countries) goes to the White Page.


Campaign Architecture

A campaign in Adset.Pro consists of several levels:

Campaign (Campaign)
    ├─ Tracking link: https://domain.com/track/{campaignId}
    ├─ Sticky Flow (on/off)
    ├─ White Page (none / url / system)
    │
    └─ Stream Set #1 (filter set + flows)
    │   ├─ Filters (applyMode: AND / OR)
    │   │   ├─ user_device = mobile
    │   │   ├─ user_os = Android
    │   │   └─ user_country IN [UA, KZ, UZ]
    │   ├─ Pixels (FB CAPI, TikTok)
    │   └─ Flows (Flows):
    │       ├─ Flow 1 (weight 70) → PWA-1 → CPA-1 → Offer-A
    │       └─ Flow 2 (weight 30) → PWA-2 → CPA-2 → Offer-B
    │
    └─ Stream Set #2 (other filters)
        ├─ Filters: user_device = desktop
        └─ Flows:
            └─ Flow 1 (weight 100) → Landing → CPA-3 → Offer-C

The tracking link of the campaign is a single URL for the traffic source. The tracker itself decides which flow to direct each click.


Stream Sets: rule sets

Stream Set is a set of filters + a list of flows. A campaign can contain multiple Stream Sets.

When a click comes in, the tracker checks the Stream Sets top to bottom (by priority) and applies the first suitable one. If no Stream Set fits — the click goes to the White Page.

Filter operation modes

Mode

Logic

When to use

AND

All conditions must match

Exact targeting (country AND device AND source)

OR

One condition is enough

Broad coverage (any of the listed countries)

Types of filters

Type

What it filters

Example keys

EVENT

Tracker event parameters

user_country, user_device, user_os, user_browser, user_lang, user_bot

HEADERS

HTTP request headers

accept-language, user-agent (raw values)

QUERY

GET parameters of the URL

utm_source, utm_campaign, fbclid, sub1..10, ext_click_id

DATE

Time and date of the click

Days of the week, hours (time schedule)

DATA

Data from external sources

IP, region, ASN organization, proxy type

Filter operators

Operator

Logic

Example

IN

Value is in the list

user_country IN [UA, KZ, UZ]

NOT_IN

Value is NOT in the list

user_country NOT_IN [US, GB]

BETWEEN

In range (for numbers/time)

hour BETWEEN [9, 21]

EXIST

Field exists and is not empty

fbclid EXIST (there is a tag from FB)

NOT_EXIST

Field is absent

fbclid NOT_EXIST

Practical examples of filters

Only mobile Android traffic:

applyMode: AND
├─ user_device IN [mobile]
└─ user_os IN [Android]

Exclude bots:

applyMode: AND
└─ user_bot IN [0]

The value user_bot = "0" for humans, "1" for bots. Important: it is the string "0", not false.

Only FB traffic (has fbclid):

applyMode: AND
└─ fbclid EXIST

Traffic from specific countries (OR):

applyMode: OR
├─ user_country IN [UA]
├─ user_country IN [KZ]
└─ user_country IN [UZ]

White Page: redirect for non-target clicks

White Page is a special URL or embedded site to which clicks that did not pass any of the Stream Sets are redirected.

Why is this needed

  • Moderators of ad networks (FB, TikTok) click on ads during verification → they need to be sent to a harmless site

  • Bots and automated scanners → White Page

  • Traffic from banned regions → White Page

  • Non-target traffic (desktop when only mobile is needed) → White Page

Types of White Page in Adset.Pro

Type

How it works

When to use

NONE

Click without routing gets 404

When there is no need for filtering

URL

302 redirect to an external URL

Simple option: link to a neutral site

SYSTEM

HTML is served inline from the same domain (via S3 + nginx)

For moderation: URL does not change, the page looks like a regular site

Option disableTrackWhiteList: If enabled — SOURCE_FILTER events for clicks that went to the White Page are not recorded in ClickHouse. Useful when you need to exclude junk traffic from statistics.

Bridge Page: For traffic from in-app WebView (FB/Instagram/TikTok/Telegram) the tracker automatically detects WebView and serves Bridge Page instead of PWA. Bridge Page kicks the user into an external browser:

  • Android → intent:// scheme → Chrome

  • iOS → x-safari-https:// → Safari

This is necessary because in-app WebView sees the DOM/redirect chain of PWA, which can trigger blocking.


Flows and weights

Inside the Stream Set, each flow (Flow) is assigned a weight — a number that determines the share of traffic. By default, weight = 100.

Example:

Flow A — "1win offer"   — weight 70  → receives 70% of clicks
Flow B — "parimatch"    — weight 30  → receives 30% of clicks

Weights can be any numbers — the tracker automatically normalizes them into percentages. The selection of Flow occurs randomly considering weights (pickWeighted).

Flow structure

Each Flow contains:

Parameter

Description

cpa

Linked CPA network (mandatory)

offer

Offer within the CPA network (mandatory)

flow

Flow in the CPA network — offer URL

pwa

Linked PWA (optional)

pwaType

PWA type: internal (builder Adset.Pro) / external (external service) / ios_app

landing

Linked landing page (optional)

landingAsPwa

Use landing in PWA mode (without a separate PWA page)

postlanding

Page after PWA subscription, before redirecting to the offer

weight

Weight of the flow (default 100)

isActive

Is the flow active (default true)

Sticky Flow

Sticky Flow solves an important A/B testing problem: one user should not see two different options.

How it works:

  • Upon the first visit, the tracker selects a Flow (by filters and weights)

  • The selection is saved in cookie sf_{campaignId} (format: setId:flowId[:clickId])

  • Upon repeat visit, the tracker reads the cookie and serves the same Flow

  • The cookie has an almost infinite lifespan

Sticky Flow settings:

Parameter

What it does

stickyFlow

Enables/disables Sticky Flow

stickyFlowKeepClickId

Saves the original clickId in cookie — repeat visit gets the same clickId for attribution

stickyFlowSkipInactive

If true — uses the saved Flow even if it is deactivated (isActive = false). If false — resets the cookie and recalculates the Flow

When to enable:

  • A/B test of two PWA designs — one user should not see both

  • Test of two offers — to correctly compare LTV

  • When user experience consistency is important


A/B testing

Step-by-step scenario of A/B testing two PWAs:

  1. Create a campaign with one Stream Set

  2. Add two Flows with weights 50/50 (weight 100 and 100):

    • Flow A → PWA-1 ("bonus" design) → CPA-1 → Offer-1

    • Flow B → PWA-2 ("game" design) → CPA-2 → Offer-2

  3. Enable Sticky Flow — so the user sees only one option

  4. Launch traffic from one source

  5. Wait for at least 100+ installs on each Flow (the more, the more accurate the result)

  6. Compare metrics in statistics with group by cmp_flow:

    • click_to_install_rate — which PWA converts better

    • cpa_accept — where there are more deposits

    • ltv_per_ftd — where users bring more in the long term

How long to test:

  • Minimum 3-5 days (to capture different days of the week)

  • Minimum 100 installs on each variant for basic statistics

  • For LTV comparison — at least 2-4 weeks (otherwise D1-7 will be incomplete)


Pixels in Stream Sets

You can attach pixels (Facebook CAPI, TikTok Events API, HTTP Get) to each Stream Set:

  • The pixel triggers on specific events (PWA installation, registration, deposit)

  • Supported events: LAND_VIEW, LAND_CLICK, PWA_VIEW, PWA_INSTALL, NOTIFICATION_SUBSCRIBE, CPA_HOLD, CPA_ACCEPT, CPA_REDEP, CPA_DECLINE, CPA_TRASH

  • Mapping is configured: tracker event → pixel event

Why attach at the Stream Set level:

  • Different traffic sources require different pixels (FB CAPI for FB traffic, TikTok Events API for TikTok)

  • One Stream Set = one source = one pixel — clean and does not conflict

Pixel Override via URL: If you add ?pixel=fb_pixel_id,tiktok_pixel_id to the tracking link, these pixels will override the pixels from the Stream Set settings. Useful for dynamic pixel binding without changing the campaign.


How the tracker processes a click: step by step

  1. A click comes in on the campaign tracking link

  2. The tracker generates event_click_id (UUID), determines parameters: country, device, user-agent, IP, ASN, proxy

  3. In-app WebView check: If the click is from WebView (FB/Instagram/TikTok/Telegram) — serves Bridge Page to kick into an external browser

  4. Checks Sticky Flow cookie (sf_{campaignId}):

    • Cookie exists → restores saved Flow (and clickId if stickyFlowKeepClickId)

    • Cookie does not exist → moves to filters

  5. Applies bot filtering

  6. Sequentially checks Stream Sets top to bottom (applySetFilters)

  7. Finds the first suitable Stream Set (all filters matched by AND/OR mode)

  8. Inside the Stream Set selects Flow by weights (pickWeighted)

  9. Saves Sticky Flow cookie (if enabled)

  10. Records the SOURCE_CLICK event with full campaign parameters

  11. Redirects the user: Landing → PWA → Offer URL (with paramTemplate)

If no Stream Set fits:

  • Records SOURCE_FILTER (if disableTrackWhiteList = false)

  • User is redirected to White Page


Recommended filters

For Facebook traffic

Stream Set #1 (main):
applyMode: AND
├─ user_bot IN [0]           ← exclude bots
├─ user_device IN [mobile]   ← only mobile
├─ user_os IN [Android]      ← Android (iOS usually a separate campaign)
└─ fbclid EXIST              ← only traffic from FB (has fbclid)

For TikTok traffic

Stream Set #1:
applyMode: AND
├─ user_bot IN [0]
├─ user_device IN [mobile]
└─ ext_click_id EXIST        ← has external click_id from TikTok

Universal (anti-fraud)

Any Stream Set:
├─ user_bot IN [0]           ← humans
├─ user_proxy IN [0]         ← no proxies (optional)
└─ user_device IN [mobile]   ← mobile

Frequently Asked Questions

Q: Why did one click end up in the "wrong" flow?

If Sticky Flow is off — this is normal. Distribution by weights is random. With weights 50/50, a specific click has an equal chance of landing in any Flow. To ensure a user always lands in one Flow — enable Sticky Flow. You can check distribution through statistics with group by cmp_flow.

Q: Can I change flow weights without stopping the campaign?

Yes. Changes in Stream Sets are applied instantly — new clicks will use the updated weights. Already recorded events do not change. Changes are made in campaign settings → Stream Set → editing flow weights.

Q: Why is traffic going to the White Page, although I created a Stream Set for this traffic?

Typical reasons:

  1. Order of Stream Sets — another Stream Set higher on the list intercepts traffic (check priority)

  2. AND mode does not match — one of the AND conditions is not met. Example: filter requires user_device = mobile, but a desktop came in

  3. Incorrect values — filter user_country IN [UK] will not work for GB (ISO code for the UK = GB, not UK)

  4. EXIST filter did not work — for example fbclid EXIST, but traffic is not from FB

Q: How to ensure that a bot does not reach the offer?

Add the filter user_bot IN [0] (the value must be the string "0") to all Stream Sets. Adset.Pro identifies bots through MaxMind + User-Agent analysis. Bot clicks will go to the White Page.

Q: What is landingAsPwa and when to use it?

If landingAsPwa = true, the landing is used as a PWA page — without a separate PWA structure. The user sees the landing, is offered "Add to Home Screen", and after installation, click_id is passed to the offer. Convenient for quick launches without creating a separate PWA.