Gatsby GDPR Cookie Banner how to implement multiple cookies + disable tracking? - javascript

So I set up a basic cookie banner following the gatsby-plugin-gdpr-cookies plugin and I used react-cookie-consent but it only shows a simple we use cookies on our website with an accept button.
How do I pass in both google analytics and google tag manager in my cookieconsent component? The docs only show one cookieName and I don't know how to add more than just the google analytics?
Also, how do I check if it actually disables cookie tracking?
I added the plugin to my gatsby-config.js
{
resolve: `gatsby-plugin-gdpr-cookies`,
options: {
googleAnalytics: {
trackingId: 'YOUR_GOOGLE_ANALYTICS_TRACKING_ID', // leave empty if you want to disable the tracker
cookieName: 'gatsby-gdpr-google-analytics', // default
anonymize: true, // default
allowAdFeatures: false // default
},
googleTagManager: {
trackingId: 'YOUR_GOOGLE_TAG_MANAGER_TRACKING_ID', // leave empty if you want to disable the tracker
cookieName: 'gatsby-gdpr-google-tagmanager', // default
dataLayerName: 'dataLayer', // default
},
facebookPixel: {
pixelId: 'YOUR_FACEBOOK_PIXEL_ID', // leave empty if you want to disable the tracker
cookieName: 'gatsby-gdpr-facebook-pixel', // default
},
// defines the environments where the tracking should be available - default is ["production"]
environments: ['production', 'development']
},
},
Then I added the Cookie Banner to my layout.js
<CookieConsent
location="bottom"
buttonText="Accept"
declineButtonText="Decline"
cookieName="gatsby-gdpr-google-analytics"
>
This website uses cookies to enhance the user experience.
</CookieConsent>
Plus the cookie only tracks gatsby-gdpr-google-analytics but i need it to track gatsby-gdpr-google-tagmanager as well

Both questions have the same answer: you have to initialize the tracking once the user has clicked the "Accept" button. That will untrack everything until the user accepts the consent. To start tracking when the user accepts it:
import { useLocation } from "#reach/router" // this helps tracking the location
import { initializeAndTrack } from 'gatsby-plugin-gdpr-cookies'
And inside your accept function (onAccept):
initializeAndTrack(location)
In addition, according to the documentation of the react-cookie-consent package, you have exposed an onDecline event that is triggered when the user rejects the GDPR policy. To allow it, you must add the enableDeclineButton property.
<CookieConsent
enableDeclineButton
onDecline={() => {
alert("nay!");
}}
></CookieConsent>
You can set a parameter, local storage, or another cookie there.
Your final code should look like:
<CookieConsent
enableDeclineButton
onDecline={() => {
alert("nay!"); // your stuff here
}}
onAccept={() => {
initializeAndTrack(location)
}}
location="bottom"
buttonText="Accept"
declineButtonText="Decline"
cookieName="gatsby-gdpr-google-analytics">
This website uses cookies to enhance the user experience.
</CookieConsent>

To answer your question, you can import Cookies (from js-cookie) and set cookies manually with the onAccept function.
Something like this
import CookieConsent, { Cookies } from "react-cookie-consent";
<CookieConsent
location="bottom"
buttonText="Accept"
declineButtonText="Decline"
cookieName="gatsby-gdpr-google-analytics"
onAccept={() => {
Cookies.set("gatsby-gdpr-google-tagmanager", true)
}}
>
This site uses cookies ...
</CookieConsent>

Related

How to properly control the google analytics cookie from javascript?

Currently I have set up the cookie prompt to override document.cookie set method, so that it stores non-required cookies and waits for user input (which cookies the user allows to use in the web page) to decide about other cookies.
Code looks something like this:
const originalSetter = document.__lookupSetter__('cookie');
function newSetter(cookie) {
if (isRequired(cookie)) {
originalSetter(cookie);
}
else {
//store the cookie and decide later.
}
}
document.__defineSetter__('cookie', newSetter);
Since the google analytics cookie is not a required one (at least in my page), is this the correct approach or is there another way to do this?

Rails 6 with js-cookie library: cookie is set but not persistent

I've been trying to set up a very simple cookie just to see if the user has clicked the cookie consent banner. I'm trying to set the cookie with an expiration date in the future so the user doesn't get this message every visit. It works to set the cookie, but it only sets it for the current session. In IE11, it doesn't work at all.
My JavaScript for this is:
in custom.js:
import Cookies from 'js.cookie';
// Hide cookie disclaimer on agreement
$('.cookies-disclaimer button').on('click', function() {
$('.cookies-disclaimer').hide();
Cookies.set('cookies_consent', true, { expires: 365, sameSite: 'strict' });
});
// Check if the cookie disclaimer has already been accepted
function hideAlreadyAcceptedCookieDisclaimer() {
var consent = Cookies.get('cookies_consent');
if (!consent) {
$('.cookies-disclaimer').show();
}
}
hideAlreadyAcceptedCookieDisclaimer();
in my application.js I require the js file from node_modules:
require('js-cookie/src/js.cookie')
...
require('custom')
UPDATE:
The problem seemed to be in the way I imported the file:
I removed import Cookies from 'js.cookie'; from custom.js
In my application.js I added the library with window.Cookies = require('js-cookie/src/js.cookie')
All credits to this post for helping me out: https://discuss.rubyonrails.org/t/js-cookie/73808 and his original blogpost: https://translate.google.com/translate?hl=&sl=ru&tl=en&u=https%3A%2F%2Ftheglitchy.com%2Fn%2Fkak-ustanovit-js-cookie-na-rails-6-yarn-webpack

Gatsby/React - Get Referring Url

Building a jobs board. Need to know if the user clicked on our link from monster.com, jobs.com, foobar.com, etc. This needs to happen in the code, as I need to send it to an API.
What is the best way to accomplish this?
I tried searching around, but can only find articles on internal routing, e.g.:
How to get previous url in react gatsby
If I need to do this in plain Javascript (not available "out-of-the-box"), please point me in the right direction there too. Not even sure what to google for this other than "UTM parameters". We are using Google Analytics and the marketing team is including utm params in the links, if that helps.
In gatsby each page component has a location prop with some useful info. So you could do something like:
import React from "react"
const IndexPage = ({ location }) => {
console.log(location.search.split("?")[1].split("&"))
return (
<div>
My homepage
</div>
)
}
export default IndexPage
So visiting https://myapp.com/?campaign=foo&id=bar would log ["campaign=foo", "id=bar"]. With that info, you could decide how and when to communicate with your APIs to log the relevant info.
This question was very vague, because I did not understand what I was asking when I posted it. There is two scenarios here that should help you get started. If you have specific questions, follow up - I will try to help.
Scenario 1 (will most likely NOT work, but here for completeness): You are getting referrals from websites you are not at all associated with. For example, you run mycoolsite.com and someone at someforum.com linked to you. The ONLY way you are going to be able to know this without anything additional is if someforum.com sends something called a Referer Request Header. Many popular sites do not.
Scenario 2: Your marketing team pays someone to link to you for a specific promotion. E.g., your marketing team tells someforum.com to link mycoolsite.com for money or as a favor. In this case, they can request that scenario 1 be followed OR, more likely, they can include something called utm params, e.g. when they send the link it's not mycoolsite.com?utm_campaign=monster&utm_source=monsterjobs
When the request comes in to your site, you can then pull these utm params out, to identify which campaign is working.
The code for that looks something like this:
function buildUtmInfoString(currentUrlString) {
const url = new URL(currentUrlString);
let referrerString = '';
utmParamNames.forEach(paramName => {
const paramValue = url.searchParams.get(paramName.standard);
if(!paramValue) {
return;
}
const paramString = `${paramName.colloquial}: ${paramValue}, `;
referrerString += paramString;
});
referrerString = referrerString.substring(0, referrerString.length-2);
return referrerString;
}
Note that you might need to look up utm param standard names, they are supported by Google Analytics out of the box, if your company uses that, but you can use them without GA.
const standardUtmParamNames = {
SOURCE: 'utm_source',
MEDIUM: 'utm_medium',
CAMPAIGN: 'utm_campaign',
TERM: 'utm_term',
CONTENT: 'utm_content'
};
const utmParamNames = [
{
standard: standardUtmParamNames.SOURCE,
colloquial: 'Source'
},
{
standard: standardUtmParamNames.MEDIUM,
colloquial: 'Medium'
},
{
standard: standardUtmParamNames.CAMPAIGN,
colloquial: 'Campaign'
},
{
standard: standardUtmParamNames.TERM,
colloquial: 'Term'
},
{
standard: standardUtmParamNames.CONTENT,
colloquial: 'Content'
}
];
export default utmParamNames;
Note that there are also hacks to accomplish this, but they are not reliable and can be seen as abuse of your user's privacy, so they aren't viable business solutions and I don't recommend wasting time on them.

Firebase custom claim how to set?

I'm struggling with firebase custom claims.
I have tested a lot of approaches nothing works. Obviously, I miss something important in the concept itself.
So I'm back to the root. This script from the google example should apply customs rule on a newly created user
exports.processSignUp = functions.auth.user().onCreate(event => {
const user = event.data; // The Firebase user.
const customClaims = {
param: true,
accessLevel: 9
};
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, customClaims)
});
Then on a client, I check the result with
firebase.auth().currentUser.getIdTokenResult()
.then((idTokenResult) => {
// Confirm the user is an Admin.
console.log(idTokenResult.claims)
if (!!idTokenResult.claims.param) {
// Show admin UI.
console.log("param")
} else {
// Show regular user UI.
console.log("no param")
}
})
.catch((error) => {
console.log(error);
});
Everything just a raw copy-paste still doesn't work. I've tested both from the local machine(there could be troubles with cors?) and deployed
This is a race situation. If the Function end first then, you will get the updated data.
The getIdTokenResult method does force refresh but if the custom claim is not ready then, it is pointless.
You need to set another data control structure to trigger the force refresh on the client. By example a real-time listener to the rtd;
root.child(`permissions/${uid}`).on..
And the logic inside the listener would be: if the value for that node exists and is a number greater than some threshold, then trigger the user auth refresh
During that time the ui can reflect a loading state if there is no datasnapshot or the not admin view if the datasnapshot exists but is a lower permission level.
In Functions you have to set the node after the claim is set:
..setCustomUserClaims(..).then(
ref.setValue(9)
);
I have a more detailed example on pastebin
The claims on the client are populated when the client gets an ID token from the server. The ID token is valid for an hour, after which the SDK automatically refreshes it.
By the time the Cloud Functions auth.user().onCreate gets called, the client has already gotten the ID token for the new user. This means that it can take up to an hour before the client sees the updated claims.
If you want the client to get the custom claims before that, you can force it to refresh the token. But in this video our security experts recommend (that you consider) using a different storage mechanism for claims that you want to be applied straight away.

Getting "remember" option to work with Firebase's authAnonymously

I'm trying to use Firebase's anonymous authentication to store data about users who visit my site. But I'm having trouble getting it to work as described.
Here's a simplified snippet of the relevant code:
var firebase_root = new Firebase('https://example.firebaseio.com');
firebase_root.authAnonymously(function(error, authData) {
var page = firebase_root.child(uid).push(); // create a unique reference for this pageload
page.child('loaded_page').set(Firebase.ServerValue.TIMESTAMP);
page.child('left_page').onDisconnect().set(Firebase.ServerValue.TIMESTAMP);
});
In the docs for anonymous authentication, it says
If not specified - or set to default - sessions are persisted for as long as you have configured in the Login & Auth tab of your Firebase's Dashboard.
I've set my Session Length to 12 months in my settings so I would expect that if I load this page and then refresh the page I would get a structure like this:
{
someRandomUserId: {
randomPageId_1: {
loaded_page: timestamp_1,
left_page: timestamp_2
},
randomPageId_2: {
loaded_page: timestamp_3
}
}
}
But it looks like it is actually re-assigning the user ID rather than persisting it across page loads. So I'm actually getting a structure like this:
{
someRandomUserId_1: {
randomPageId_1: {
loaded_page: timestamp_1,
left_page: timestamp_2
}
},
someRandomUserId_2: {
randomPageId_2: {
loaded_page: timestamp_3
}
}
}
Am I doing something wrong or is this a bug?
You're creating a new authentication session each and every time you invoke FirebaseRef.authAnonymously(...). This method only needs to be invoked once, after which the user will authenticated upon page refreshes.
If you'd like to check for the current authentication state of the user, and only then create a new authentication session if the user is not currently authenticated, use the synchronous accessor for authentication state FirebaseRef.getAuth().

Categories