Overview
Web Server-to-Server (Web S2S) sends web conversion and engagement events to Singular directly
from your server, using the same EVENT endpoint as the mobile V1 integration. The web path is
differentiated by the platform parameter p=Web.
Web S2S is a browser-assisted architecture. Several attribution-relevant values
are only available in the browser — location.href,
document.referrer, and the browser userAgent
cannot be reconstructed on the backend. A thin client-side snippet must collect these values and
either call the endpoint directly or forward them to your backend, which then makes the S2S call.
There is no web SESSION endpoint. The first
__PAGE_VISIT__ conversion event replaces the mobile
launch call and establishes the attribution baseline for the visit.
Web S2S shares authentication, encoding, and common-parameter conventions with the rest of the S2S suite. See the S2S Fundamentals hub and the EVENT endpoint reference.
Endpoint
Web S2S uses the same host and path as the mobile V1 EVENT endpoint. Set
p=Web to route the request through the web attribution path.
GET https://s2s.singular.net/api/v1/evt
SDID Generation and Persistence
The Singular device ID (sdid) ties all events from one browser to a
single web device. On first page load, if no global_singular_id exists
in localStorage, generate a UUID v4 and store it. Reuse the same value
as sdid on every event from that browser until
localStorage is cleared.
If the Web SDK is present on the page, reuse the value it already set in
global_singular_id rather than generating a new one.
function getOrCreateSDID() {
var KEY = 'global_singular_id';
var sdid = localStorage.getItem(KEY);
if (!sdid) {
sdid = crypto.randomUUID(); // UUID v4
localStorage.setItem(KEY, sdid);
}
return sdid;
}
The __PAGE_VISIT__ Pattern
The first event of any new visit MUST be __PAGE_VISIT__ with
conversion_event=true. This establishes the attribution baseline that
later events inherit.
Send a new __PAGE_VISIT__ with
conversion_event=true whenever the same browser returns from a
different campaign (different UTM or partner). Reuse the same
sdid, and send the __PAGE_VISIT__ before
any other events for that visit.
Non-conversion events (for example sng_registration_complete or
sng_purchase) use conversion_event=false and
omit attribution_data. They inherit attribution from the
most recent __PAGE_VISIT__.
A non-conversion event that arrives before its conversion event is deferred one minute while the backend waits for a match.
custom_user_id rules
- Include
custom_user_idafter registration or login, and on all subsequent events. - Persist it in
localStorageor a first-party cookie. - Drop it on logout.
- Never include PII. Use a hashed or internal ID.
Parameters
The Web SDK sends roughly 40 parameters on __PAGE_VISIT__, but most are
SDK-internal telemetry that S2S developers should not replicate. The tables below cover the required
and recommended sets only.
Authentication (a) and other shared conventions are documented once in
the hub. See
Common
Parameters in S2S Fundamentals.
Required parameters
| Parameter | Details |
|---|---|
a |
Singular API key from your dashboard. See Common Parameters. Example: |
p |
Platform. Always Example: |
i |
Bundle ID of the web app/site in Singular. Must match the Web SDK Product ID. Find it under Settings > Apps > expand the web app > Bundle ID. Example: |
n |
Event name. The first event of a visit must be Example: |
sdid |
Singular device ID. Use the same value set by the Web SDK
( Example: |
conversion_event |
Set Example: |
attribution_data |
Click-through data from ad networks, URL-encoded JSON. Required on
Example:
|
custom_user_id |
Your internal user ID. No PII. Include after registration/login and on subsequent events; drop on logout. Example: |
ip |
Device IP at the time of the event. Example: |
web_url |
The conversion landing page URL, including its marketing parameters. This is the last URL
that contained marketing params, stored like the SDID and reused. It is used by the backend to
create the attribution touchpoint. Distinct from
Example:
|
Recommended parameters
| Parameter | Details |
|---|---|
device_user_agent |
The browser user agent ( Example: |
web_page_referrer |
The referrer of the current page ( Example: |
timezone |
The device timezone. Example: |
os |
The device operating system. Example: |
screen_width |
Screen width in pixels. Example: |
screen_height |
Screen height in pixels. Example: |
utime |
Event time in UNIX time (seconds). Example: |
URL and referrer parameters — do not conflate.
web_url and web_page_referrer are
attribution-relevant and are used by the pipeline. web_page_url (the
current page, window.location.href) and
document_referrer are event-logging only and are
silently dropped for attribution. Do not send web_page_url or
document_referrer expecting them to affect attribution.
For device identity and other shared parameters not listed above, see the Common Parameters in S2S Fundamentals rather than re-documenting them here.
attribution_data
The attribution_data parameter carries click-through data from ad
networks as URL-encoded JSON. Send it on __PAGE_VISIT__ conversion events
only.
{
"partner_name": "Snapchat",
"is_attributed": "true",
"touch_timestamp": "",
"partner_campaign_id": "",
"partner_campaign_name": "Snap_campaign_1234",
"partner_creative_id": "",
"partner_creative_name": "",
"partner_keyword": "",
"partner_site": "",
"partner_site_id": "",
"partner_site_name": "",
"partner_sub_site": "",
"partner_sub_site_name": "",
"partner_subcampaign_id": "",
"partner_subcampaign_name": "",
"_p": ""
}
Required fields
| Field | Details |
|---|---|
partner_name |
Mapped from the web param Example: |
is_attributed |
Set Example: |
partner_campaign_name |
Mapped from the web param Example: |
Optional fields
| Field | Details |
|---|---|
touch_timestamp |
Touchpoint time in UNIX seconds. Example: |
partner_campaign_id |
Mapped from the web param |
partner_creative_id |
Mapped from the web param |
partner_creative_name |
Mapped from the web param |
partner_keyword |
Mapped from the web param |
partner_site_id |
Mapped from the web param |
partner_site_name |
Mapped from the web param |
partner_sub_site_name |
Mapped from the web param |
partner_subcampaign_id |
Mapped from the web param |
partner_subcampaign_name |
Mapped from the web param |
Web click IDs in the e param
Pass network click IDs in the event e payload using the JSON key each
partner expects:
| Partner | Click ID key(s) |
|---|---|
| Snapchat | ScCid |
| TikTok | ttclid |
gclid, gbraid,
wbraid
|
|
| DV360 | dclid |
fbclid |
|
rdt_uuid |
Marketing-param detection. Treat a landing URL as a touchpoint when it contains
any of: utm_*; Singular wp*
(wpsrc, wpcn,
wpcid, and similar); Singular pc*/
p* (pcid,
pcn, psrc, and similar);
clid; or kw/an/
ud. On a match, store the full URL as
web_url and fire a conversion event.
Web-to-App Attribution
To carry web campaign context into a mobile click, build a Singular Link from your landing page and append the captured landing query string. This forwards the marketing parameters to the mobile click so the app install can be attributed.
On landing, capture window.location.search (plus fragment) when it
contains marketing params and persist it. When rendering the app-store or smart-banner link, build:
function buildWebToAppLink(baseLink, webUrl, deeplink, passthrough, deferredDeeplink) {
var url = new URL(baseLink); // preserves existing base-link params
if (webUrl) {
var q = new URL(webUrl);
var captured = q.search.slice(1) + (q.hash || ''); // landing query string (+fragment)
url.searchParams.set('_web_params', captured); // URL-encoded on serialization
}
if (deeplink) url.searchParams.set('_dl', deeplink);
if (passthrough) url.searchParams.set('_p', passthrough);
if (deferredDeeplink) url.searchParams.set('_ddl', deferredDeeplink);
return url.toString();
}
| Appended param | Details |
|---|---|
_web_params |
URL-encoded query string (plus fragment) of the captured landing
|
_dl |
Deep link argument. Optional. |
_p |
Passthrough argument. Optional. |
_ddl |
Deferred deep link argument. Optional. |
Accuracy: the SDID is not appended to the link (no
_dsid or _sdid). This is
campaign-parameter forwarding, not deterministic SDID device-stitching.
Clipboard Attribution (Deferred Deep Link)
Clipboard attribution provides a deterministic match for a deferred deep link. The web snippet writes a unique token to the clipboard; the freshly installed app reads it back and matches on token equality.
function openAppWithClipboardDdl(baseLink, deeplink, passthrough, deferredDeeplink) {
// 1. Build the web-to-app link (see Web-to-App Attribution).
var link = buildWebToAppLink(baseLink, capturedWebUrl, deeplink, passthrough, deferredDeeplink);
// 2. Generate a UUID v4 and form the token.
var uuid = crypto.randomUUID();
var tokenUrl = location.protocol + '//' + location.hostname + '/__singular_ddl__/' + uuid;
// 3. Write ONLY the token to the clipboard (execCommand fallback).
copyToClipboard(tokenUrl);
// 4. Append the token to the click as ecid.
var url = new URL(link);
url.searchParams.set('ecid', tokenUrl);
// 5. Open the app / store.
window.open(url.toString());
}
function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text);
return;
}
var ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
Accuracy: the clipboard holds only the token — not the SDID,
not _web_params, and not the deep link. The match is token equality
(ecid on the click equals the clipboard token), so the freshly installed
app matches deterministically.
The clipboard write must run inside a user-gesture handler (a click) or browsers block it. Note iOS Safari clipboard constraints.
Reading the clipboard on first launch is the app side's concern (its own mobile SDK/S2S integration), not this web snippet.
Event Sequence Examples
First visit and registration
-
User arrives from Google Ads. Send the initial page visit:
n=__PAGE_VISIT__conversion_event=truesdid=3730aecb-47ba-4d13-bd17-52b4b700956fattribution_data={ "partner_name": "googleadwords_int", "is_attributed": "true", "partner_campaign_name": "brand_us_en" }
-
User registers. Send the registration event:
n=sng_registration_completeconversion_event=false-
sdid=3730aecb-47ba-4d13-bd17-52b4b700956f(same SDID) custom_user_id=user_12345abc- No
attribution_data
Returning user from a new campaign
-
The same browser returns from a different campaign. Send a new page visit:
n=__PAGE_VISIT__conversion_event=true-
sdid=3730aecb-47ba-4d13-bd17-52b4b700956f(same SDID) attribution_data={ "partner_name": "facebook", "is_attributed": "true", "partner_campaign_name": "retargeting_Q1" }
-
User purchases. Send the purchase event:
n=sng_purchaseconversion_event=false-
sdid=3730aecb-47ba-4d13-bd17-52b4b700956f(same SDID) - Persisted
custom_user_id - No
attribution_data