Shopify Review Technical Notes
Disclaimers
- Luxifer and ux-pro were our old product names. Much of the architecture still references them.
- We do NOT use level 2 customer data such as names or emails (referenced here)
- We DO use level 1, behavior, DOM interactions, ecommerce data, demographic information, etc.
Data sent to endpoints external to Shopify
1. OpenID Connect ID Token (docs)
Purpose
- When enabling tracking via the Shopify admin UI, the
app.idToken()is sent to our backend in order to retrieve necessary project data. The token is used to verify that the request came from a Shopify authenticated user.
Input
- The cloud function is public, but verifies the following
apiSecretmust match our Shopify api secret (using jwtVerify from jose)audmust match our app client idexpmust be after the time of callnbfmust be before the time of calldestmust exist as a URL related to one of the projects within Lummmen systems- Decoded and parsed payload has header and payload
- If any of these fail, the cloud function returns a generic 401 even in the case of malformed input
Output
matomoId– The associated Matomo project that was created priorsampple– The percentage of users tracked, for limiting throughput burdenname– The name of the project
Architecture
- Shopify admin UI — Source and destination of the workflow
- Google cloud run/firebase functions — Processing, validation & query project data
- Firestore — Project data source
2. Matomo-based Analytics Data
Purpose
- Core of the Lummmen tool. Allows for the main structure of tracking (sessions).
Privacy
visitorConsentCollectedis listened to from the document- consent status controls whether Lummmen can send data or not
Input
lummmen_site_idfrom a Shopify metafield (same asmatomoId). Comes from admin setup (#1).visitorIdHashed and truncated fromwindow.Shopify.customerPrivacy.consentId()(docs)- Behavioral and Demographic data (see privacy policy #3 for details)
- A full list of what Matomo collects can be seen here
Architecture
- Customer browser — where the tracking code is ran
- Self hosted Azure running Matomo — destination
Integration
- Fires an event
'lummmen:startPixel’so thatvisitorIdandsiteIdcan be visible to the pixel. - In case of /checkout where the liquid never renders, saves cookies with the same values.
3. Clicktracking data
Purpose
- Supplementary data that allows Lummmen users and systems to analyze customers in high granularity.
Privacy
visitorConsentCollectedis listened to from the document- consent status controls whether Lummmen can send data or not
Input
lummmen_site_idfrom a Shopify metafield (same asmatomoId). Comes from admin setup (#1).visitorIdHashed and truncated fromwindow.Shopify.customerPrivacy.consentId()(docs)- orderId and customerId for responding to privacy webhooks.
- Mouse movements and click actions
- Timing, location and what elements were interacted with (if clickable)
- Element information does NOT include what is inside textboxes
- Element information includes tag type, classnames, ids, etc.
- see privacy policy for further details
Architecture
- Customer browser — where the tracking code is ran
- Google cloud run/firebase functions — Processing, validation & saving
- Clickhouse — destination
4. Ecommerce data (Pixel only)
Purpose
- Data that allows Lummmen users and systems to analyze customers in high granularity, track revenue and goal performance.
Privacy
visitorConsentCollectedevent frominit.customerPrivacyis listened to.- Check is performed prior to every post request.
Input
customerId,orderId– used to respond to webhooks. Not always available.- product & variant
sku,title,price,quantity,category. - Total prices, subtotals, taxes of orders.
- First party cookie or custom event data from
'lummmen:startPixel’siteId(same asmatomoIdfrom #1).visitorId/clientId. Same as in #2.
url,timestamp- type of event from the pixel (docs)
checkout_completedproduct_added_to_cartproduct_removed_from_cartproduct_viewedcollection_viewed
Architecture
- Customer browser via pixel — where the code is ran (sandboxed)
- Self hosted Azure running Matomo — destination
Webhooks
pubsub://ux-pro:shopify-compliance
The following webhooks are configured
customers/data_requestcustomers/redactshop/redactapp/uninstalled
Data is not deleted immediately. Instead, a request is saved and developers are notified.
The deletion process is manual, but the notification process is automatic.
Tickets for auditing
- A Firestore document is written as a ticket in the collection
gdprComplianceRequests - It contains the body of the webhook, the creation time, status, and platform “Shopify”
- If resolved, it contains the resolution time and the resolver.
customers/data_request & customers/redact
- In the case that the request only contains the customer email (like mentioned here), requests cannot be fulfilled as we do not save customer emails.
- We save orderId and customerId in ecommerce events where available.
- ecommerce events also have a visitorId which is the hashed consentId. (docs)
- Using the visitorId, we can link it to and delete any data that contains this key.
- If the data request can be fulfilled, it will be emailed to the store owner.
- Aggregate data cannot be reasonably linked back to individuals so cannot be requested or redacted.
shop/redact
- The redact payload has a URL which we can trace back to a project on our end.
- This project and all of the related project data has a common key which we will use for deletion.
app/uninstalled
- We record this request but do not take any action. We expect Shopify to send a shop/redact 48 hours after.
For the future
- Develop a process where non-technical admins can respond to and resolve these requests.