DoConure

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 its dataLayer.
  • The app host carries nothing. The console, the admin, the signing pages and the verification page have no banner and no tag. /signup is the one public page on the app host.

The cookies and identifiers

NameSet byForLasts
doconure_consentus, the bannerremember the choice (version, statistics 0/1, advertising 0/1, time)6 months
doconure_internalus, an operatorkeep an operator’s browser out of the data180 days
sessionus, on the app host only (sign-in and the sign-up form)the console session and the forms’ anti-forgery token12 hours
_ga, _ga_*Google Analytics, after statisticstell visits apartper Google (up to 2 years)
_gcl_*Google Ads, after advertisingthe click that led hereper Google (90 days)
_fbp, _fbcMeta, after advertisingthe campaign clickper Meta (90 days)
LinkedIn Insight cookiesLinkedIn, after advertisingcampaign measurementper LinkedIn
OpenAI pixel storageOpenAI, after advertisingcampaign measurementper 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

  1. 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 its linkedin_conversion_rules), openai_pixel_id. Each empty one is a channel that is off.
  2. For server-side events add the secrets to infra/doconure.env on the server (never in a form): GA4_API_SECRET, OPENAI_CONVERSIONS_API_KEY, LINKEDIN_CONVERSIONS_TOKEN. Production also sets TRACKING_ENABLED=1; staging and development never do, which is why nothing is ever sent from them.
  3. 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.
  4. Open the Tracking page: every channel shows off, simulated, validate or live.

Testing with GA4 DebugView

  1. On the Tracking page choose exclude this browser and press Mark as internal. The tags load in this browser with traffic_type: internal and debug_mode.
  2. 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.
  3. For the server side press Validate next to Google Analytics 4: it sends one test event to /debug/mp/collect and 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.

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.