Tracking, consent and the ad platforms
The public site (the home page, the legal pages, the contact form, the guide and
/signup) can measure visits and campaigns. It is off until an id is set, and nothing
leaves the visitor’s browser until they say yes. This page is for whoever runs the
campaigns.
How it works
- Consent, ours. A banner served from our own domain, in Italian (English on the English pages), with Rifiuta tutto as prominent as Accetta tutto and a panel per purpose: necessary, statistics, advertising. The choice is kept six months in a first-party cookie; a link in every footer reopens it. Google Consent Mode v2 starts with every signal denied and is updated on the choice.
- No request to a third party before a consent. The page reads one small file from
its own domain (
/tracking-config.json, public ids only) to learn which channels are on. If none is on — or the deployment is not production — there is no banner and no tag. - Each tag loads only for its purpose. Statistics: Google Analytics 4. Advertising:
Google Ads, Meta, LinkedIn, OpenAI. With a Tag Manager container set, Tag Manager loads instead of
gtag.js, after the consent defaults; the same events reach itsdataLayer. - The app host carries nothing. The console, the admin, the signing pages and the
verification page have no banner and no tag.
/signupis the one public page on the app host.
The cookies and identifiers
| Name | Set by | For | Lasts |
|---|---|---|---|
doconure_consent | us, the banner | remember the choice (version, statistics 0/1, advertising 0/1, time) | 6 months |
doconure_internal | us, an operator | keep an operator’s browser out of the data | 180 days |
session | us, on the app host only (sign-in and the sign-up form) | the console session and the forms’ anti-forgery token | 12 hours |
_ga, _ga_* | Google Analytics, after statistics | tell visits apart | per Google (up to 2 years) |
_gcl_* | Google Ads, after advertising | the click that led here | per Google (90 days) |
_fbp, _fbc | Meta, after advertising | the campaign click | per Meta (90 days) |
| LinkedIn Insight cookies | LinkedIn, after advertising | campaign measurement | per LinkedIn |
| OpenAI pixel storage | OpenAI, after advertising | campaign measurement | per OpenAI |
Our own campaign record (the UTM labels, the landing page and the click id carried through the sign-up form) is separate and needs no cookie.
Setting it up
- In Settings, group Tracking and ads, enter the public ids:
ga4_measurement_id(G-...),gtm_container_id(GTM-..., optional),google_ads_id(AW-...),meta_pixel_id,linkedin_partner_id(and itslinkedin_conversion_rules),openai_pixel_id. Each empty one is a channel that is off. - For server-side events add the secrets to
infra/doconure.envon the server (never in a form):GA4_API_SECRET,OPENAI_CONVERSIONS_API_KEY,LINKEDIN_CONVERSIONS_TOKEN. Production also setsTRACKING_ENABLED=1; staging and development never do, which is why nothing is ever sent from them. - Choose the server mode: SIMULATED (the default: events are recorded on the Tracking page, nothing is sent), VALIDATE (the provider’s validation endpoint, nothing is counted) or LIVE.
- Open the Tracking page: every channel shows off, simulated, validate or live.
Testing with GA4 DebugView
- On the Tracking page choose exclude this browser and press Mark as internal.
The tags load in this browser with
traffic_type: internalanddebug_mode. - Open the public site, accept statistics in the banner, and in Google Analytics open
Admin > DebugView: your page views and events appear there. GA4’s Internal Traffic
filter (set to active once, on
traffic_type = internal) keeps them out of the reports. - For the server side press Validate next to Google Analytics 4: it sends one test event
to
/debug/mp/collectand shows Google’s answer.
Excluding a browser
No tracking at all shows no banner and loads no tag in that browser. Mark as internal
loads them with traffic_type: internal. Remove returns it to an ordinary visitor. The
cookie is doconure_internal, on the registrable domain, so the public site and the app host both
see it. Do it once per browser.
Server events
Five events are sent from the server, never from a request: sign_up (registration
verified), first_pdf, first_signature, purchase (net value, currency,
transaction id; the first one also flagged first_purchase) and credit_gift_spent.
They are queued with the thing they report and sent by the outbound sweep; a failed send is retried and
then marked failed. Each has a stable id, so a platform can de-duplicate. The payload holds numbers and
ids only: never an email, a name, a phone number, an IP address or a document.
They go to Google Analytics 4, LinkedIn and OpenAI. Meta gets none: its Conversions API needs the browser’s user agent, which we never send, so Meta has only its pixel in the browser, after consent. Google Ads gets none either: its conversions leave as the CSV below.
An event is skipped, with the reason on the Tracking page, when: the deployment is not production; the organisation is a test organisation; a verified address of it is on an internal domain (the registration bypass list); the visitor did not consent to the provider’s purpose (statistics for Google Analytics, advertising for the others) or came from an excluded browser; the payment was simulated; or the platform has no identifier for the visit.
Google Ads: the offline conversions
Download the CSV from the Tracking page and import it under Conversions > Uploads. It holds the click id, the conversion name, the time (UTC), the value and currency and an order id, for people who consented to advertising and arrived on a Google click. The download is recorded in the audit trail.