Skip to content

Consent and cookie banner

The app can record what the user does in the store, such as the products they view or what they add to the cart, to send them reminders like the abandoned cart one. It can also measure app usage with Firebase Analytics. Both need the user’s consent.

That consent is usually requested in the website’s cookie banner. Inside the app, the banner has to tell the app what the user has chosen. A single JavaScript call, window.ReskytLayout.consent.set(...), in the buttons the banner already has, is enough.

  1. Add a function to the website’s JavaScript that translates the banner’s choice into the app’s format.
  2. Call it every time the user accepts, rejects or saves their preferences, and also on every page load if they had already answered.
  3. Keep a permanent link to the cookie settings inside the app, so the user can change their mind.

window.ReskytLayout only exists inside the app. In a normal browser the call does nothing, so the same code works for the website and for the app.

Each banner group corresponds to one or more app keys:

Banner groupWhat it allows in the appKeyIf the user has not answered yet
Strictly necessaryNothing additional.NoneAlways on.
AnalyticsFirebase Analytics measuring app usage.analyticsStorageOn, unless the Firebase Analytics module settings say otherwise.
Personalisation or behaviouralThe User Journal recording shopping activity, and reminders based on it, such as the abandoned cart one.journalOff in every app.
AdvertisingAdvertising cookies and identifiers, sending data to Google for advertising, and personalised advertising.adStorage, adUserData and adPersonalizationOff.

The analytics and advertising keys correspond to Google’s consent mode keys (analytics_storage, ad_storage, ad_user_data and ad_personalization) and are passed to Firebase one to one. If analyticsStorage is off, Firebase collects nothing.

The app stores the answer on the device itself, together with the date. From then on:

  • It does not ask again. The answer is kept even if the app is closed, and Reskyt does not request it again.
  • It applies at once. The app checks the answer every time it is about to record something, so a change mid-session takes effect immediately, in both directions.
  • The last answer wins. It does not matter whether it comes from the website’s banner or from Reskyt’s consent page.

This function receives the groups the user has accepted in the banner and passes them to the app. It can go anywhere in the website’s JavaScript:

function applyAppConsent(groups) {
const consent = window.ReskytLayout?.consent;
// Outside the app, or if the app is not ready yet, it does nothing
if (!consent?.isAvailable()) return;
consent.set({
journal: groups.behavioural === true,
analyticsStorage: groups.analytics === true,
adStorage: groups.advertising === true,
adUserData: groups.advertising === true,
adPersonalization: groups.advertising === true,
});
}

The names behavioural, analytics and advertising are an example: replace them with the ones your banner uses. A group that does not arrive as true is turned off.

The function is called at four moments, always the same way:

WhenWhat is called
The user clicks Accept allapplyAppConsent({ analytics: true, behavioural: true, advertising: true })
The user clicks Reject all or Only necessaryapplyAppConsent({}), which turns everything off
The user saves their preferencesapplyAppConsent(...) with the value of each checkbox
A page loads and the user had already answeredapplyAppConsent(...) with the answer the website has stored

The last case keeps the app aligned with the answer the website stores, for example in a cookie, even if the banner is not shown again.

If the website uses a consent manager, the call is made from the event the manager fires when the choice changes, instead of from the buttons:

ManagerEvent
OneTrustOptanonWrapper()
CookiebotCookiebotOnAccept and CookiebotOnDecline
Didomiconsent.changed

The accepted groups are read from the manager’s own API.

Withdrawing consent must be as easy as giving it. Keep a permanent link to the cookie settings inside the app, in the footer or the menu, that reopens the banner. If the user rejects from there, the banner calls applyAppConsent({}) or directly ReskytLayout.consent.set('none').

To make the app ask again, for example when the consent stored on the website expires, call ReskytLayout.consent.reset().

Instead of your own banner, the website can open the consent page included in the app:

window.ReskytLayout.screens.openSystemPage('consent');

The app never opens it on its own: it has to be called from the website’s code, for example from a button. The page only needs to be published in the backoffice; it needs no other setting.

If the device’s browser has a privacy option such as Do Not Track or Global Privacy Control turned on, the app turns everything off, whatever the banner answered.

Open the app on a test device with the web inspector attached, from chrome://inspect on Android or from Safari’s Develop menu on iOS, and run ReskytLayout.consent.get() in the console:

SituationWhat it should return
Before answering the bannerstatus: 'undecided' and journal: false
After Accept allstatus: 'decided', source: 'user' and every key true
After Reject all from the cookie settingsEvery key false

If it returns source: 'browser' with everything off, the device has a browser privacy option turned on, as explained in the previous section.

MethodWhat it does
isAvailable()Indicates whether the API can be used. Returns false outside the app.
get()Returns the stored answer.
set(choice)Stores an answer. Returns a promise with the new state.
reset()Clears the answer and returns to the unanswered state.
onChange(listener)Runs listener every time the answer changes. Returns a function to stop listening.

set accepts three forms:

ValueEffect
'all'Turns everything on.
'none'Turns everything off.
An object, for example { journal: true }Changes only the given keys. The rest keep their value.

You can store your own keys, with letters, digits and underscore up to 64 characters. The app stores them and returns them in get(), but does not use them.

get() returns an object with this shape:

{
status: 'decided',
source: 'user',
decidedAt: '2026-10-21T09:12:00.000Z',
categories: {
journal: true,
analyticsStorage: true,
adStorage: false,
adUserData: false,
adPersonalization: false
}
}
FieldMeaning
status'undecided' if the user has not answered yet, 'decided' if they have.
sourceWhere the value comes from: 'default', the default values; 'user', the user’s answer; 'browser', a browser privacy option that turns everything off.
decidedAtDate of the answer.
categoriesThe value of each key.

To read it from the website, for example to not show the banner inside the app if the user has already answered:

const consent = window.ReskytLayout?.consent;
if (consent?.get().status === 'decided') hideBanner();
consent?.onChange((state) => console.log(state.categories));