Server-to-Server (S2S) Measurement
Advanced measurement where you send data directly from your server to the Sklik endpoint.
S2S is suitable for websites where you need maximum accuracy without relying on third-party cookies. It can also be used for measuring conversions from mobile applications or for sending offline conversions.
The frontend script (sul.js) is required even for S2S
Even with S2S measurement, the frontend script sul.js must be deployed on the website with your SEM ID. It creates cookies sid and udid that you must read and pass in every S2S request. The S2S payload itself also contains SEM ID (parameter sem_id) – that is a different identifier. Without cookies from sul.js, user identity cannot be correctly matched.
Prerequisites
- Frontend script deployed on all pages of the website (generates cookies
sidandudid) - Ability to read cookies
sidandudidfrom the server - Ability to hash personal data with SHA-256 on the server
- SEM ID for S2S – a special identifier used exclusively for S2S measurement. It differs from the standard SEM ID (for the script and GTM). See Where to find SEM ID? If you have Seznam Shopping store outlets, each outlet has its own SEM ID for S2S.
Endpoint
Send all S2S requests as POST to:
POST https://sem.seznam.cz/rtgconv
Content-Type: application/json
HTTP headers
| Header | Required | Description |
|---|---|---|
Content-Type | Required | Always application/json |
X-Client-Id | Recommended | Name of your application or library sending the data (e.g. my-eshop-plugin, shoptet-sem) |
X-Client-Version | Recommended | Application version (e.g. 1.4.2) |
Why provide X-Client-Id and X-Client-Version?
These headers help us debug issues on your side – we can quickly identify which application and version sent the data. They have no effect on event processing, but significantly speed up diagnostics.
User identification
The S2S payload must contain the sid and udid cookies generated by the frontend script. Read them on the frontend and pass them to the server, where you include them in the user_ids.user_data object.
sid and udid require user consent
The sid and udid cookies are only written by the frontend script after consent with ad_storage: 'granted' is received. Make sure your website passes consent via updateConsent (or uses IAB TCF) before the first PageView – otherwise the cookies will not be available and user session matching will not be possible. See Setting up consent for details.
function getCookie(name) {
const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
return match ? decodeURIComponent(match[1]) : null;
}
const sid = getCookie('sid'); // pass to server as user_ids.user_data.sid
const udid = getCookie('udid'); // pass to server as user_ids.user_data.udid
Another key identifier is sznaiid – the click ID from Sklik. This value is found in the URL parameter after a click on an ad and is used for anonymous conversion modelling. It can be safely stored on the server without user consent.
Hash personal data before sending
Unlike the frontend script, which hashes automatically, with S2S you must hash yourself using SHA-256 all personal data fields: em, ph, fn, ln, ge, db, ct, zp, sr, country. Exception: review_email must not be hashed even with S2S.
Payload structure
| Parameter | Type | Required | Description |
|---|---|---|---|
schema_version | string | Required | Always "v2" |
event_name | string | Required | Event name, e.g. "Purchase" |
event_type | string | Required | Always "rtgconv" |
event_time | integer | Required | Unix timestamp in milliseconds (UTC) |
event_url | string | Required | URL of the page where the event occurred |
event_source | string | Required | "web" or "app" |
event_id | string | Recommended | Unique event ID (ideally UUID-7) for deduplication |
user_ids | object | Required | Object with user identifiers (see below) |
event_data | object | Required | Event data – same structure as frontend measurement (see Event reference) + parameters sem_id and sznaiid |
consent_string | string | Recommended | IIAB TCF consent string (if available) |
consent_mode | object | Recommended | Google Consent Mode (alternative to TCF) |
s2s_headers | object | Recommended | IP address and User Agent for more accurate identification |
user_ids.user_data object
| Parameter | Description | Hash? |
|---|---|---|
sid | Session cookie from seznam.cz – read from browser | No |
udid | Session cookie generated by sul.js | No |
em | User email address (key identifier) | Yes (SHA-256) |
ph | Phone number | Yes (SHA-256) |
fn | First name | Yes (SHA-256) |
ln | Last name | Yes (SHA-256) |
ge | Gender (m, f or o) | Yes (SHA-256) |
db | Date of birth (format YYYYMMDD) | Yes (SHA-256) |
ct | City | Yes (SHA-256) |
zp | Postal code | Yes (SHA-256) |
sr | Street and house number | Yes (SHA-256) |
country | Country code (ISO 3166-1 alpha-2, e.g. cz) | Yes (SHA-256) |
Special parameters in event_data for S2S
| Parameter | Required | Description |
|---|---|---|
sem_id | Required for S2S | SEM ID for S2S – a separate identifier visible after enabling advanced settings. Different from the SEM ID for the script/GTM. |
sznaiid | Recommended | Click ID from Sklik – URL parameter after clicking on an ad. Used for anonymous conversion modelling. |
Complete payload example
{
"schema_version": "v2",
"event_source": "web",
"event_name": "Purchase",
"event_type": "rtgconv",
"event_time": 1770134113676,
"event_id": "018e4f2a-1234-7abc-9def-0123456789ab",
"event_url": "https://vas-eshop.cz/dekujeme",
"user_ids": {
"user_data": {
// Cookies from sul.js – read from browser (do not hash)
"sid": "id=1922397029101872874|t=1737450723.526|te=1756971615.061|c=0F247CCA",
"udid": "01958f34-71d5-7ec2-ae01-cb3c80a1d0a0",
// Personal data – hash with SHA-256 on the server
"em": "6db68d052788e70eb459463eb34370fe983ef838db65641902f02326fabc37a7",
"ph": "ca6faa7abf120a739e8ce3bcf581553af9ad983b3290ed8cdf8cc40b9d4fefcf",
"fn": "6a0ac0fd972c325d6ca5512b67a5e0ad996c4a3e9b59971d125164e6d4db1a1c",
"ln": "64118260ecb916c23621d8f2768d8dc75d1f5710b1b7e4f2c41ad41e6bc4d688",
"ct": "f377db9f1f0af132866afd5c4381512a5c9a3b3a32e9ca2f88f0aced18264568"
}
},
"consent_mode": {
"ad_storage": "granted",
"ad_user_data": "granted",
"ad_personalization": "granted",
"functionality_storage": "denied",
"analytics_storage": "denied"
},
"s2s_headers": {
"client_ip_address": "77.75.74.172",
"user_agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36...",
"sec_ch_ua_mobile": "?0",
"sec_ch_ua_platform": "\"Windows\""
},
"event_data": {
"sem_id": "VASE_SEM_ID_PRO_S2S",
"sznaiid": "2627214859780792651",
"order_id": "OBJ-987654",
"content_type": "product",
"currency": "CZK", // only CZK is supported
"value": 27364, // total value excluding VAT (in CZK)
"value_tax": 5746,
"delivery_type": "CESKA_POSTA",
"delivery_price": 121, // including VAT
"other_costs": -500, // discount including VAT
"payment_type": "karta",
"contents": [
{
"id": "ABC12345",
"quantity": 1,
"unit_price": 33490, // including VAT
"content_name": "iPhone 15 Pro Max",
"content_category": "Elektronika | Mobilní telefony | Apple"
}
]
}
}
Sending the request
Send the payload as an HTTP POST request to the endpoint https://sem.seznam.cz/rtgconv with the Content-Type: application/json header.
curl -X POST https://sem.seznam.cz/rtgconv \
-H "Content-Type: application/json" \
-H "X-Client-Id: my-eshop-plugin" \
-H "X-Client-Version: 1.0.0" \
-d '{ ... your payload ... }'
await fetch('https://sem.seznam.cz/rtgconv', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Client-Id': 'my-eshop-plugin',
'X-Client-Version': '1.0.0',
},
body: JSON.stringify(payload)
});
import requests
response = requests.post(
'https://sem.seznam.cz/rtgconv',
json=payload,
headers={
'X-Client-Id': 'vas-eshop-plugin',
'X-Client-Version': '1.0.0',
}
)
response.raise_for_status()
Error handling and recommendations
| HTTP status | Meaning | Recommended action |
|---|---|---|
200 OK | Event received and processed | – |
400 Bad Request | Invalid payload – missing required field or incorrect format | Fix the payload, do not retry automatically |
401 / 403 | Invalid SEM ID or inaccessible endpoint | Check the SEM ID for S2S |
5xx | Server-side error | Retry with exponential backoff (see below) |
Retry strategy
For 5xx errors or network timeouts, we recommend retrying the request with exponential backoff: 1 s → 2 s → 4 s, up to 3 attempts. Do not retry 4xx errors – they indicate a problem with the payload, not a temporary outage.
Timeout
Set the request timeout to 3–5 seconds. S2S calls must not block order processing on your server – send events asynchronously (e.g. in a background queue).