Google Analytics 4 & Meta (Facebook) tracking for booking
A guide for merchants on how to connect Google Analytics 4 (GA4) and the Meta (Facebook) Pixel to your booking products in Periode, how to make sure ad clicks are actually tracked, and how to embed the booking flow in an iframe on your own website.
How tracking works in Periode
Periode tracks completed bookings as server-to-server conversions. You do not need to add a GA4 or Meta Pixel snippet to the Periode booking pages. Periode sends the purchase event directly to Google and Meta from the backend when a booking is completed.
The setup has two steps for each platform:
- Register your credentials once under
Settings > Integrations. - Turn the integration on for each booking product that should report conversions.
Setting this up over the API. Both steps can be scripted — useful when you provision many customers from your own tooling. Register the credentials with
POST /merchants/:id/integrationSecrets, then setga4Integration/metaIntegration(the credentialname) on each booking product viaPUT /merchants/:id/products/booking/:productId. See the Integrations guide for the request bodies. Nothing needs to be sent to Periode — each customer’s own measurement IDs and tokens stay in their own merchant.
For a conversion to be attributed to your campaign, the visitor’s click ID
(gclid for Google Ads, fbclid for Meta) has to reach Periode. Periode reads
these from the URL when the customer opens a Periode page, so how you link to
Periode from your ads matters. See the next section.
Most important: make sure the ad click reaches Periode
Attribution only works if the click ID is present in the URL when the customer lands on a Periode page. Periode reads the following query parameters from the landing URL and remembers them, for the merchant whose page the customer landed on, while they complete the booking:
gclid: sent by Google Ads (auto-tagging). Attributes the booking to Google.fbclid: sent by Meta / Facebook Ads. Attributes the booking to Meta.client_id: from your GA4 setup. Stitches the booking to a GA4 user.session_id: from your GA4 setup. Stitches the booking to a GA4 session.
There are two supported ways to make this work.
Option A (recommended): link your ads directly to the booking product
Point the ad’s destination URL straight at the Periode booking product:
https://minside.periode.no/booking/<merchantId>/<bookingManifestId>
Google Ads and Meta automatically append gclid and fbclid to the destination
URL, so when the ad points directly at Periode, the click ID arrives on its own
and the conversion is tracked. No extra work needed.
You can find a product’s booking URL in the Backoffice, or use the short link
https://minside.periode.no/b/<bookingManifestId>.
Option B: if you route through your own website first, forward the parameters
If your ad sends the customer to your own website first (for example your
front page) and then on to Periode, the gclid or fbclid lands on your
page, not on Periode. In that case you must carry the parameters over to the
Periode link (or iframe src) yourself, otherwise the click ID never reaches
Periode and the booking is not attributed.
When you build the link or iframe that opens Periode, append the same parameters you received:
https://minside.periode.no/booking/<merchantId>/<bookingManifestId>?gclid=<gclid>&fbclid=<fbclid>
If you use GA4 and want the booking stitched to the visitor’s GA4 session, also
pass client_id and session_id (read from your own GA4 or gtag setup):
...?client_id=<gaClientId>&session_id=<gaSessionId>
The booking visit: Periode keeps the click ID in the browser’s memory for as long as the customer stays on the booking page — nothing is stored in a cookie. The booking must be completed in the same visit as the customer arrives with the parameter, or the conversion won’t be attributed. The values belong to the merchant whose page the customer landed on, and are never applied to a booking with another merchant.
Part 1: Google Analytics 4
What you need from Google
- Measurement ID: looks like
G-XXXXXXXXXX(in Google Analytics,Admin > Data streams > your web stream). - API Secret: created under the same web stream
(
Measurement Protocol API secrets > Create).
Step 1: Register GA4 in Periode
- In the Backoffice, go to
Settings > Integrations. - Click Google analytics 4.
- Fill in:
- Name: a label of your choice, e.g.
Main website. Used only to identify the integration inside Periode. - Measurement ID: your
G-XXXXXXXXXXID. - API Secret: the secret you created in Google.
- Name: a label of your choice, e.g.
- Save.
Step 2: Enable GA4 on a booking product
- Open the booking product you want to track
(
Booking > Products, thenEditon the product). - Go to the Admin section.
- Under Google Analytics 4 integration, select the GA4 integration you registered in Step 1.
- Save.
From now on, every completed booking of that product sends a GA4 purchase
event (transaction ID, value, and currency) via the Measurement Protocol.
Customer details (email, name, phone) are sent as SHA-256 hashed user-provided
data, in line with Google’s requirements — no readable personal data is sent to
GA4 — and only for bookings that carry a granted consent, see
Customer consent.
To let GA4 use the hashed customer details, enable User-provided data collection in Google Analytics (
Admin > Data collection and modification > Data collection).
Repeat Step 2 for each product you want to track. The integration is enabled per product, not globally.
Customer consent
If you keep the customer’s consent decision on your own site, Periode can take it with the booking and report accordingly.
Every booking carries the consent values you send and returns them in the bookings API and the webhook. They also decide what Periode passes on to Google and Meta: customer details and the ad click ID go only with a granted consent.
Passing consent from your own consent banner
If you already ask for consent — a cookie banner on your site, a consent screen
in your app — pass the answer on the booking link, alongside gclid and the
other campaign parameters:
| Parameter | Value |
|---|---|
ad_user_data | granted or denied |
ad_user_data_at | the moment the customer answered, ISO 8601 in UTC |
One answer covers advertising measurement and ad personalization together —
Periode sets GA4’s ad_user_data and ad_personalization to the same value. It
is deliberately all or nothing, so customers face one question rather than
several.
/booking/<merchantId>/<productId>?ad_user_data=granted&ad_user_data_at=2026-09-20T09:15:00Z
Both values are stored on the booking and come back in the bookings API and the booking webhook:
| Field on the booking | Comes from | Value |
|---|---|---|
gclid | gclid | as sent |
fbclid | fbclid | as sent |
gaClientId | client_id | as sent |
gaSessionId | session_id | as sent |
adUserData | ad_user_data | true for granted, false for denied |
adUserDataAt | ad_user_data_at | as sent |
The consent answer is stored as a boolean: ad_user_data=granted comes back as
adUserData: true, and denied as adUserData: false.
A parameter you do not send is left absent on the booking rather than filled
with a default, so absence means “no answer” and is distinct from false.
The four campaign identifiers are kept and stored whatever the consent value says — they are yours, and you may need them to do your own reporting. Consent governs what Periode sends onward to Google and Meta, not what it keeps for you.
If you embed the booking flow in an iframe, forward the parameters onto the
iframe src.
The consent Periode records is the one you send on the link. A customer who arrives without it has no answer recorded on that booking.
What is sent
With adUserData set to true, the booking is reported in full: the
hashed customer details, and the gclid / fbclid from the ad click.
Otherwise — denied, or no answer at all — the booking is still reported, but only as a purchase, with no customer details, no click ID and no session ID:
- GA4 gets the
purchaseevent withad_user_data: DENIED, carrying the product, price, currency and transaction ID. The Measurement Protocol requires aclient_idon every request, so Periode derives one from the transaction instead of reusing the customer’s. That keeps the purchase unlinked, at the cost of GA4 counting each such booking as a new user — expect consentless bookings to show up as single-event sessions rather than joining a customer’s history. - Meta gets the
Purchaseevent identified only byexternal_id, a hash of the booking ID. It identifies the booking rather than the person, so the purchase shows up in Events Manager but cannot be matched to a Meta profile or attributed to an ad.
If you send all conversions yourself from your own server-side container, leave the GA4 and Meta integrations switched off in Periode. The booking still stores and returns everything above, so you have what you need.
Part 2: Meta (Facebook) Pixel
Setup mirrors GA4.
What you need from Meta
- Pixel ID: a numeric ID from
Meta Events Manager > your dataset. - Access Token: a Conversions API access token generated for that dataset
(
Settings > Conversions API > Generate access token).
Step 1: Register Meta in Periode
- Go to
Settings > Integrations. - Click Meta.
- Fill in:
- Name: a label of your choice, e.g.
Facebook ads. - Access token: your Conversions API token.
- Pixel ID: your numeric Pixel ID.
- Name: a label of your choice, e.g.
- Save.
Step 2: Enable Meta on a booking product
- Open the booking product (
Booking > Products, thenEditon the product). - Go to the Admin section.
- Under Meta Pixel API integration, select the Meta integration you registered.
- Save.
Completed bookings now send a Meta Conversions API Purchase event. Customer
details (email, name, phone) are hashed before being sent, in line with Meta’s
requirements, and only for bookings that carry a granted consent — see
Customer consent.
Part 3: Embedding the booking flow in an iframe
You can embed Periode’s booking flow inside a page on your own website using an
<iframe>. This lets customers book without leaving your site, while Periode
still handles the booking, payment, and confirmation.
Remember the rule above: if you embed Periode in an iframe from a page that received an ad click, forward
gclidandfbclidonto the iframesrcso attribution still works (Option B).
The confirmation view
After a booking is paid, the customer lands on Periode’s booking confirmation page:
https://minside.periode.no/bookings/<merchantId>/<bookingId>
Adding ?slim=true renders a slim version of this page. Chrome and
navigation are stripped away so it fits cleanly inside an iframe:
https://minside.periode.no/bookings/<merchantId>/<bookingId>?slim=true
Sending the customer to the confirmation page (Redirect URL)
To control where the customer goes after a completed booking, set a redirect URL on the product itself:
- Open the booking product (
Booking > Products, thenEditon the product). - Go to
Details > Advanced. - Fill in the field “Redirect after completed purchase with query param: bookingId”.
When a booking is completed, Periode redirects the customer to this URL and appends the booking ID as a query parameter:
https://your-site.example/thank-you?bookingId=<bookingId>
Do not paste a hinted path with {bookingId} and expect Periode to replace it.
Periode appends the booking ID as a query parameter (?bookingId=<id>). Build
the redirect page so it reads that parameter and loads the matching confirmation
or thank-you content.
Any campaign and consent values stored on the booking are appended too, under the same names you would have sent them in on the booking link:
| Parameter | From the booking |
|---|---|
gclid / fbclid | the ad click that led to the booking |
client_id / session_id | the GA4 identifiers you passed in |
ad_user_data | granted or denied |
ad_user_data_at | when the customer answered |
https://your-site.example/thank-you?bookingId=<bookingId>&gclid=<gclid>&ad_user_data=granted
A value that is not on the booking is left out, so only the parameters you actually have come back. Because the names match the inbound ones, your thank-you page can read them the same way your landing page does — useful for firing your own conversion tag with the right click ID, and for setting Consent Mode on the page from the answer the customer already gave.
The click IDs come back whatever the consent answer says: they are your data on your own site. Consent governs what Periode sends onward to Google and Meta, as described under Customer consent.
The purchase event for your own GA4 / GTM
When the slim confirmation page loads inside an iframe, Periode also pushes a client-side ecommerce event so that your own Google Tag Manager or GA4 (the one running on your website, outside Periode) can pick up the conversion.
Because the event is fired inside the iframe, Periode relays it to the parent page
with postMessage. Add a listener on your page to forward it into your own
dataLayer:
<script>
window.addEventListener('message', function (event) {
// Only trust messages coming from Periode
if (event.origin !== 'https://minside.periode.no') return;
if (!event.data || event.data.source !== 'periode') return;
if (event.data.event === 'periodePurchase') {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'periodePurchase',
ecommerce: event.data.ecommerce,
});
}
});
</script>
The ecommerce payload contains the standard fields you can use to configure a
purchase tag in GTM:
{
"transaction_id": "<bookingId>",
"value": 499.0,
"currency": "NOK",
"items": [{ "item_id": "<bookingProductId>", "item_name": "<bookingProductName>", "price": 499.0, "quantity": 1 }]
}
Values are sent in major currency units. For example, a NOK 499.00 booking is
sent as 499.0, not 49900.
The event fires once per booking (it is de-duplicated per transaction), so a customer who reloads the confirmation page will not trigger a second conversion.
Which method should I use?
- Report conversions to your GA4 property: Part 1 (server-side, no code on your site).
- Report conversions to Meta / Facebook Ads: Part 2 (server-side, no code on your site).
- Make sure ad clicks are attributed: link ads directly to the booking product, or forward the URL parameters (the “Most important” section).
- Show the booking flow inside your own website: Part 3 (iframe plus redirect URL).
- Fire a purchase event in your own GTM or GA4 on your site: Part 3
(
periodePurchaseviapostMessage).
The server-side integrations (Parts 1 and 2) and the iframe dataLayer event
(Part 3) are independent. You can use either, or both together.