Skip to content

Commit

Permalink
pc/consent: Fides.shopify integration function (#2152)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssangervasi authored Jan 10, 2023
1 parent 8ea5e8b commit 34c3da3
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 20 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ The types of changes are:
* Add link to Classify Systems page in nav side bar [#2128](https://github.com/ethyca/fides/pull/2128)
* Dataset classification UI now polls for results [#2123](https://github.com/ethyca/fides/pull/2123)
* Update Privacy Center Icons [#1800](https://github.com/ethyca/fides/pull/2139)
* Privacy Center `fides-consent.js`:
* `Fides.shopify` integration function. [#2152](https://github.com/ethyca/fides/pull/2152)
* Dedicated folder for integrations.

### Changed

Expand Down
1 change: 1 addition & 0 deletions clients/privacy-center/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"rules": {
"curly": ["error", "all"],
"nonblock-statement-body-position": ["error", "below"],
"import/prefer-default-export": "off",
"react/jsx-filename-extension": [1, { "extensions": [".tsx"] }],
"react/jsx-props-no-spreading": [0],
"react/function-component-definition": [
Expand Down
2 changes: 1 addition & 1 deletion clients/privacy-center/cypress/e2e/consent.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe("Consent settings", () => {
cy.getByTestId("card").contains("Manage your consent").click();

cy.getByTestId("consent-request-form").within(() => {
cy.get("input").type("test@example.com");
cy.get("input#email").type("test@example.com");
cy.get("button").contains("Continue").click();
});
cy.wait("@postConsentRequest");
Expand Down
52 changes: 49 additions & 3 deletions clients/privacy-center/packages/fides-consent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,36 @@ In this example, `data_sales` is a cookie key that has been [configured in the P

The build process for this package pulls in the consent configuration from the Privacy Center's
`config.json`. This includes the `cookieKeys` for each consent item as the default options for a
user that has not modified their consent.
user that has not modified their consent.

For example, the default configuration includes a consent option for advertising:

```json
{
"consent": {
"consentOptions": [
{
"fidesDataUseKey": "advertising",
"name": "Data Sales or Sharing",
"default": true,
"cookieKeys": ["data_sales"]
}
]
}
}
```

When a user visits a page that includes `fides-consent.js` with this configuration, the value of
`Fides.consent.data_sales` will be set to `true` by default.

If the user visits the Privacy Center and removes their consent for advertising, this choice is
saved in their browser. Subsequent visits to pages that include `fides-consent.js` will have
`Fides.consent.data_sales` set to `false`.


## Google Tag Manager
## Integrations

### Google Tag Manager

Once Fides is loaded in a page, calling `Fides.gtm()` will push the user's consent
choices into GTM's dataLayer under `Fides.consent`.
Expand All @@ -59,7 +85,27 @@ if (Fides.consent.data_sales) {
}
```

## fides-consent.mjs & fides-consent.d.ts
### Shopify

To integrate with Shopify's [Consent Tracking API](https://shopify.dev/api/consent-tracking?shpxid=7e81a186-C696-4E23-F327-E7F38E5FF5EE#consent-collection),
call `Fides.shopify(options)`, where options is an with the following properties:

- `tracking`: The only consent option Shopify currently supports. Refer to their [visitor tracking](https://shopify.dev/api/consent-tracking#visitor-tracking) documentation.

For example, with the default Privacy Center configuration:

```html
<head>
<!-- The script can be loaded in the store's theme, or in a custom pixel. -->
<script src="example.com/privacy-center/fides-consent.js"></script>
<script>Fides.shopify({ tracking: Fides.consent.data_sales })</script>
<head>
```

Note that `data_sales` is just an example cookie key. You may configure other data uses that should
be considered tracking, whose cookie key you would pass as the `tracking` option instead.

## fides-consent.mjs & fides-consent.d.ts

This package also exports its library (`src/lib`) as a module the Privacy Center can import. This ensures the Privacy Center uses the exact same logic for reading & writing cookie data. This module is only used locally for convenience and is not published.

Expand Down
26 changes: 10 additions & 16 deletions clients/privacy-center/packages/fides-consent/src/fides-consent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// This file is created at build time by `generateConsentConfig` in `rollup.config.js`.
import consentConfig from "./consent-config.json";

import { gtm } from "./integrations/gtm";
import { shopify } from "./integrations/shopify";
import { getConsentCookie } from "./lib/cookie";

const Fides = {
Expand All @@ -14,22 +16,14 @@ const Fides = {
*/
consent: getConsentCookie(consentConfig.defaults),

/**
* Call this to configure Google Tag Manager. The user's consent choices will be
* pushed into GTM's `dataLayer` under `Fides.consent`.
*/
gtm() {
if (typeof window === "undefined") {
return;
}

const dataLayer: any[] = (window as any)?.dataLayer ?? [];
dataLayer.push({
Fides: {
consent: Fides.consent,
},
});
},
gtm,
shopify,
};

declare global {
interface Window {
Fides: typeof Fides;
}
}

export default Fides;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
declare global {
interface Window {
dataLayer?: any[];
}
}

/**
* Call Fides.gtm to configure Google Tag Manager. The user's consent choices will be
* pushed into GTM's `dataLayer` under `Fides.consent`.
*/
export const gtm = () => {
const dataLayer = window.dataLayer ?? [];
dataLayer.push({
Fides: {
consent: window.Fides.consent,
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
declare global {
interface Window {
Shopify?: {
/** https://shopify.dev/api/consent-tracking#loading-pattern-for-visitor-tracking */
loadFeatures(
features: Array<{ name: string; version: string }>,
callback: (error: Error) => void
): void;
customerPrivacy?: {
/** https://shopify.dev/api/consent-tracking#settrackingconsent-consent-boolean-callback-function */
setTrackingConsent(consent: boolean, callback: () => void): void;
};
};
}
}

type ShopifyOptions = {
tracking: boolean | undefined;
};

const applyOptions = (options: ShopifyOptions) => {
if (!window.Shopify?.customerPrivacy) {
throw Error("Fides could not access Shopify's customerPrivacy API");
}

window.Shopify.customerPrivacy.setTrackingConsent(
Boolean(options.tracking),
() => {}
);
};

/**
* Call Fides.shopify to configure Shopify customer privacy. Currently the only consent option
* Shopify allows to be configured is user tracking.
*
* @example
* Fides.shopify({ tracking: Fides.consent.data_sales })
*/
export const shopify = (options: ShopifyOptions) => {
if (!window.Shopify) {
throw Error(
"Fides.shopify was called but Shopify is not present in the page."
);
}

// If the API is already present, simply call it.
if (window.Shopify.customerPrivacy) {
applyOptions(options);
return;
}

// Otherwise we need to load the feature before applying the options.
window.Shopify.loadFeatures(
[
{
name: "consent-tracking-api",
version: "0.1",
},
],
(error) => {
if (error) {
throw Error("Fides could not load Shopify's consent-tracking-api");
}

applyOptions(options);
}
);
};

0 comments on commit 34c3da3

Please sign in to comment.