The server resolves the user’s location from request headers. These are optional but strongly recommended — sending them skips the server-side IP lookup and reduces latency.
If none of the above headers are sent, the server falls back to IP-based geolocation using X-Forwarded-For. For direct calls (browser or mobile app → our API), this is handled automatically by the load balancer. If you’re proxying requests through your own backend, you must forward the user’s IP via X-Forwarded-For — otherwise the server sees your server’s IP and geo will be wrong.
If unsure about which headers to send, contact marco@thrads.ai and we’ll help you set it up.
Unique, anonymous user identifier (e.g. a UUID like user_a1b2c3d4-...). Must be stable across sessions for the same user. Do not use email, name, or other PII. On web, store in localStorage; on mobile, use the platform’s persistent storage (e.g. UserDefaults on iOS, SharedPreferences on Android).
contextual only Conversation identifier. One unique ID per conversation, not per user. Reset when user starts a new chat. Required when request_type is "contextual".
contextual only Conversation history. Required when request_type is "contextual". Each message must have a role ("user" or "assistant") and content. PII (names, emails, addresses, etc.) should be masked or removed before sending.
Publisher configuration for pacing, creative constraints, and analytics. All fields are optional — omitted fields fall back to defaults set on your chatbot in the platform dashboard.
Maximum character length for ad headlines. Minimum value is 30. When set, the system guarantees no headline exceeds this limit — creatives that don’t fit are filtered or replaced.
contextual only Current turn number in the conversation. Used for ad offset pacing and analytics. Must be >= 0. Only needed if you’re not calling the endpoint on every user-assistant exchange — if you are, the system derives this from the message count.
contextual only Number of turns since the last ad was shown in this conversation. Used by the max frequency check. Only needed if you’re not calling the endpoint on every user-assistant exchange — if you are, the system tracks this automatically.
When true, the system serves an ad as a last resort even if the conversation context doesn’t strongly match any campaign. Hard filters (banned content, geo targeting, budget caps) still apply — force never overrides safety or budget constraints.We recommend starting withoutforce (the default) and only enabling it if your fill rate is too low. See Maximising Fill Rate for guidance.
A 200 OK response with "bid": null is not an error - it means the auction ran successfully but no DSP submitted a winning bid. This is normal behavior.
Use config.experiment_tag to run A/B tests on your integration. Tag each request with a label (max 30 characters) and the tag is recorded on every impression. You can then compare performance metrics (impressions, clicks, CTR, revenue) across experiment variants in your dashboard.Example: test whether showing ads after turn 3 vs turn 5 performs better.
Split your traffic between the two variants and compare offset_3 vs offset_5 in your dashboard analytics.You can use experiment tags to test any parameter — ad offset, max frequency, headline length, image vs no-image, or anything else in your integration logic.