When a patient answers the cookie banner on your website and then clicks through to your booking page, they are asked the same question a second time. Switch this on and your website passes the answer along, so the booking page applies it instead of asking again.
Who does what: you decide and switch it on, your webmaster adds a few lines of code (section 2), and nothing changes for patients who reach the booking page any other way.
You need | Why |
A Google Tag Manager container in Crossuite | Without it the booking page has no cookie bar and nothing to reuse |
The cookie categories chosen | Only categories you offer on the booking page can be reused |
Access to your own website | Your webmaster adds the snippet to your cookie banner |
Your banner text extended | Section 3 — this is what makes reusing the answer lawful |
It only works for patients who click a link on your website. From an email, a QR code, a search result or a bookmark there is nothing to pass along, so those patients keep whatever they answered before or see our cookie bar as usual.
Exactly one thing has to be true:
By the time the browser opens the booking page, the URL must already carry the parameters.
We read them off our own URL as the page loads. There is no callback to call afterwards, no postMessage, no API — a decision that arrives later cannot be applied, because the cookie bar has already decided whether to show itself.
https://booking.crossuite.app/<your-link-id>?cc_v=1&cc_ts=1789123044&cc_analytics=1&cc_marketing=0How that URL comes about is entirely up to you. Section 2.4 lists the usual ways with their trade-offs; pick whichever fits your site.
Parameter | Required | Value | Meaning |
| yes |
| Format version. Anything else is ignored |
| yes | unix seconds | When the patient decided. Older than 182 days is ignored |
| no | max 64 characters | Your consent record id, so your log and ours can be matched |
| no |
| Statistics |
| no |
| Advertising |
| no |
| Functionality and personalisation |
Two things to get right whichever way you build the URL:
Send the current answer, not the one from first consent. cc_ts is when the patient decided, so a patient who changes their mind must produce a new value on the next click.
Leave a category out if your banner never asked about it. A 0 is a refusal; an absent parameter means "not asked" and lets our bar ask instead.
Anything other than 1 or 0 in a category counts as if the parameter were not there. A timestamp more than five minutes in the future is refused. An id longer than 64 characters is dropped, the rest of the link still applies.
The link says for a category | What happens on the booking page |
| Allowed — unless the patient refused it on our own bar, see below |
| Refused, always, whatever was stored before |
nothing | Whatever the patient answered on the booking page stays; our bar asks if there is nothing |
Three rules decide the rest:
A 0 always applies. Whatever was stored and whoever stored it, a refusal in the link takes effect — including over a consent the patient gave on our own cookie bar. Withdrawing is never blocked.
A 1 applies unless the patient refused that category on our own bar. That refusal is the one thing a link cannot overturn; only the patient can, through "Cookie preferences" in the footer. A refusal that came from your website is not final — your website may grant it again.
Only categories you offer on the booking page are applied. A cc_marketing for a practice that does not offer advertising is ignored; the rest of the link still applies.
When every category the booking page offers is answered, no cookie bar appears. When something is left unanswered, the bar appears and asks about everything.
We remove the cc_ parameters from the address as soon as we have read them, so the patient sees a clean booking URL.
Approach | Good when | Watch out for |
Rewrite the link when it is clicked | Any site, links added dynamically, no backend needed | Only fires for the clicks you listen to; the rewritten |
Rewrite when consent changes | Few, static booking links | Misses links rendered later; parameters sit in the page source |
Render the parameters server-side | Your pages are rendered per request and can read your own consent cookie | Goes stale if the patient changes consent without reloading |
Your own redirect endpoint | You want every entry point covered, including middle-click and copied links | One more route to maintain |
Rewrite on click. The usual choice. One delegated listener, no per-link setup:
document.addEventListener(
'click',
(e) => {
const link = e.target.closest('a[href*="booking.crossuite.app"]');
if (!link || !window.__cs) return;
const url = new URL(link.href);
url.searchParams.set('cc_v', '1');
url.searchParams.set('cc_ts', String(window.__cs.ts));
if (window.__cs.id) url.searchParams.set('cc_id', window.__cs.id);
for (const category of ['analytics', 'marketing', 'functionality']) {
if (window.__cs[category] !== undefined) {
url.searchParams.set(`cc_${category}`, String(window.__cs[category]));
}
}
link.href = url.toString();
},
true, // capture: runs before a router or other script can stop the event
);window.__cs is just somewhere to keep the current answer — set it from your consent platform's callback every time the patient decides. Use whatever storage suits you.
Note that click only fires for the primary button. If you want middle-click and "open in new tab" covered too, register the same handler for auxclick.
Rewrite when consent changes. In your consent callback, walk the links once:
document.querySelectorAll('a[href*="booking.crossuite.app"]').forEach(rewrite);Redirect endpoint. Point your booking links at a route of your own, read your consent cookie there and redirect to the booking URL with the parameters appended. This is the only approach that also covers middle-click, links opened in a new tab, and links copied from the page.
The booking host is booking.crossuite.app. If you match it as plain text, as the example above does, any other spelling matches nothing and the whole feature silently does nothing — compare it with a real booking link from your Crossuite settings before going live.
This is the part that makes reusing the answer lawful: your banner has to tell the patient that their choice also applies to the booking page.
Text to add to your banner or cookie policy:
Online appointment booking runs on
booking.crossuite.app, operated for us by Crossuite BV. The choice you make here is passed on to that page: the statistics and advertising cookies you allow are set there in our own Google Tag Manager container. The booking page also sets a few strictly necessary cookies for your booking, your language and your login. You can change your choice at any time through "Cookie preferences" at the bottom of the booking page. See the Bookings.
Rows to add to your cookie table:
Purpose | Set by | Type | Retention |
cookie choice | Crossuite (booking page) | strictly necessary | 6 months (182 days) |
booking progress, reservation | Crossuite (booking page) | strictly necessary | session / until the reservation expires |
language | Crossuite (booking page) | strictly necessary | session |
login, only if the patient signs in to Held | Crossuite (booking page) | strictly necessary | until they sign out |
| Google, via the booking page | strictly necessary | 6 months |
your GA4 / Ads cookies | your own GTM container | statistics / ads | as on your site |
reCAPTCHA protects the booking form from spam and cannot be switched off, so it belongs in your table even though neither you nor we set it directly.
The last row stays general on purpose: those cookies come from your container, so their names and retention are already in your own cookie table.
Settings → Webbooking → Analytics → Configure → Consent from your own website
It is off by default. Switching it on asks you to confirm two things:
Your banner covers the booking page — it names Crossuite and the booking page as a separate destination, lists the cookies with purpose and retention, and links our cookie policy.
A withdrawal on your website only reaches us when the patient clicks through again. Until then, and for at most 182 days, their earlier answer stays in force on the booking page. This is not a setting we can change: their answer lives in a cookie on your domain and the browser does not let our code read it. The patient can always withdraw directly through "Cookie preferences" in the booking page footer.
You do not need the snippet to test — paste the parameters onto your booking link by hand.
cc_ts is a unix timestamp in seconds, not a date. It is a plain number, ten digits today:
| Is | Result |
| 14 September 2026, 07:00 UTC | accepted |
| 16 March 2026 — exactly 182 days earlier | the oldest still accepted |
| one second before that | too old, the link is ignored |
| milliseconds, not seconds | far in the future, ignored |
| a date string | not a number, ignored |
Get a current value by running Math.floor(Date.now()/1000) in the browser console. The numbers above were generated on 14 September 2026 — take a fresh one rather than copying them, or your test will start failing in March 2027.
Delete the cc_cookie_* cookie before each test (DevTools → Application → Cookies), otherwise you are testing the answer already stored.
A complete test link looks like this:
https://booking.crossuite.app/<your-link-id>?cc_v=1&cc_ts=1789369239&cc_id=test-1&cc_analytics=1&cc_marketing=1&cc_functionality=1Link | Expected |
| No cookie bar, everything allowed, no |
| No cookie bar, everything refused |
| Cookie bar appears — two categories are unanswered |
| Cookie bar appears — no |
Refuse on the booking bar, then open the first link | No bar, still refused — a decision made here wins |
In Google Tag Manager preview mode the booking page pushes a crossuite_consent_update event with crossuite_consent_analytics, crossuite_consent_marketing and crossuite_consent_functionality.
If nothing happens
Work through it in this order:
Is the setting switched on in Crossuite?
Does the selector in the snippet match your real booking link, character for character?
Is cc_ts present, and less than 182 days old?
Is the category you sent one the booking page actually offers?
Did you clear the cc_cookie_* cookie?
Saving your analytics settings asks every patient again. Adding a category, editing the privacy policy or switching this feature off all raise the consent policy version, which invalidates every stored answer, reused ones included. Expect the bar to reappear for everyone after such a save — that is the policy change, not a broken transfer.
Withdrawing stays possible through "Cookie preferences" in the booking page footer. A change there affects the booking page only; nothing is written back to your website.
Every reused answer is logged with your consent record id and the timestamp you sent, so your records and ours can be matched line by line.
booking.crossuite.app is a different domain from your website. Add it to the cross-domain list of your GA4 and Google Ads setup, otherwise the gclid is lost on the way over and a booking that came from an ad is not attributed to it.