1. Access scopes we request
| Scope | What we use it for |
|---|---|
| write_products | Write the generated detail-page content (product description HTML, images) back to the merchant’s own products. |
| write_files | Upload the generated images to the merchant’s Shopify Files so the detail page can reference them. |
| write_pixels | Install the app’s own web pixel (see section 2) for anonymous traffic counting. |
| read_customer_events | Required for the app web pixel to subscribe to storefront analytics events. Non-PII: we read only the event name and product IDs. |
| write_translations | Register locale translations of the generated product description for merchants selling in multiple languages. |
Protected customer data access (base level = read_customer_personal_data, reason: Analytics)
This base-level access is the one Shopify names read_customer_personal_data. Shopify defines protected customer data as data about customers or visitors to a store. The storefront events our app pixel subscribes to (page views, product views, checkout progression) are visitor data, so the app holds base-level access with the reason Analytics. The only values the app actually handles under this access are the event name, product IDs, and the anonymous visitor identifier clientId provided by Shopify — and clientId is reduced in the browser to a one-character bucket label by a one-way hash, with the original discarded (see section 2).
We do not request the following scopes, and the app contains no API call that would use them:
- read_customers
- read_orders
- read_all_orders
- read_customer_name
- read_customer_email
- read_customer_phone
- read_customer_address
2. What the app web pixel sends
GENCY Pixel (an app pixel running in the strict sandbox) subscribes to page_viewed, product_viewed, checkout_started and checkout_completed. The complete payload sent to our server is shown below — nothing else is transmitted.
{
"shop": "example.myshopify.com",
"event": "product_viewed",
"productIds": ["1234567890"],
"variant": "A",
"ts": 1755388800000
}- productIds — the numeric portion of the product GID only.
- variant — a single character, "A" or "B", derived in the browser from a one-way djb2 hash of the Shopify-provided clientId (null when no clientId is present). It buckets anonymous visitors for A/B testing of the merchant’s own content. The clientId value itself is never transmitted to, or stored on, our servers. When the product has no running A/B test, our server records this value as "-" (excluded from comparison).
- No field of event.data.customer, checkout.email, checkout.billingAddress, checkout.shippingAddress, or checkout.order is read.
3. What we store
We store only daily aggregate counters keyed by (shop, product ID, date, variant, experiment run ID). The run ID identifies one A/B experiment, not a person. There is no per-visitor record, no identifier that can be resolved to a person, and no raw event log is retained.
4. Customer privacy consent
The pixel declares analytics = true, marketing = false, preferences = false, sale_of_data = disabled. Shopify’s pixel manager loads it only when the visitor has granted analytics consent. We do not sell or share this data, and we do not use it for behavioural advertising.
5. Mandatory compliance webhooks
All three of customers/data_request, customers/redact, and shop/redact are implemented and HMAC-verified. Because the app holds no customer personal data, the first two have no customer record to return or erase; on shop/redact we delete the store’s data.