Shopify
The Omnata Shopify plugin is able to sync data inbound and outbound.
The Omnata plugin uses the Shopify GraphQL Admin API, currently pinned to version 2026-04.
On this page, you'll find:
Authentication methods
Admin API access token
Yes
The Admin API access token of the custom app you created in Shopify. Stored as a Snowflake secret. See Generate your API Access Token.
User Tier
Yes
Your Shopify plan tier (Standard, Advanced, Shopify Plus, Enterprise). Determines the API rate limits Omnata applies. See Obtain your User Tier.
The plugin supports two ways to authenticate to your Shopify store. New connections should use Client Credentials — it's the path Shopify supports for new apps created in 2026 and beyond. The legacy Admin API access token method is retained for stores that already have an access token issued from a custom app created before 1 January 2026.
Client Credentials (Client ID / Client Secret) — recommended
API Access Token — legacy
Both methods share the same supporting fields: your shop URL and your User Tier. The next section explains those.
Common connection fields
Regardless of which authentication method you choose, every connection requires these:
User Tier
Yes
Your Shopify plan tier. Determines the API rate limits Omnata applies. See Obtain your User Tier.
Obtain your shop name
Visit your store page.
Click on Settings on the bottom left of your main store page.
Copy down your shop name from the URL of the Settings page (the part before
.myshopify.com).
Every Shopify store has a *.myshopify.com URL, even if you've configured a custom domain. Always use the myshopify.com form in the connection field.
Obtain your User Tier
In your Shopify admin, go to Settings → Plan.
Identify your current Shopify plan and choose the matching User Tier in the Omnata connection form:
Basic Shopify
Basic
Shopify
Shopify
Advanced Shopify
Advanced
Shopify Plus
Shopify Plus
Enterprise
Enterprise
The User Tier you choose drives the per-second and per-minute API rate limits Omnata applies — see Managing performance for the values.
Client Credentials (Client ID / Client Secret)
Recommended for all new connections. This method follows Shopify's OAuth 2.0 client-credentials grant — Omnata exchanges your app's Client ID and Client Secret for a short-lived Admin API access token (24-hour lifetime) and automatically refreshes it.
Connection fields
In addition to the Common connection fields above, this method requires:
Client ID
Yes
The app's Client ID, copied from the Shopify Developer Dashboard.
Client Secret
Yes
The app's Client Secret. Stored as a Snowflake secret.
Steps to obtain a Client ID and Client Secret
These steps describe the high-level flow. Shopify updates the Developer Dashboard UI from time to time — refer to Shopify's client credentials grant guide.
Sign in to the Shopify Developer Dashboard.
Create a new app. Give it a descriptive name (e.g.
Omnata Sync).Configure the app's API access scopes. We recommend granting read (and write, for outbound) access to every Shopify object you intend to sync — the scopes you'll need per stream are listed under Generate your API Access Token and apply identically here.
Install the app on the store you want to sync from. (Generate an installation URL from the dashboard and open it in a browser session for the store owner / admin.)
After installation, the app's overview page shows the Client ID and Client Secret. Copy both immediately and store the Client Secret somewhere safe — once revealed, it should be treated like a password.
Paste both values into the Omnata connection form, along with your shop URL and User Tier.
API Access Token
Legacy method. Use this only if you already have an Admin API access token from a custom app created in the Shopify admin before 1 January 2026, or if you're connecting to a store where the Client Credentials grant is not viable.
As of 1 January 2026, Shopify discontinued the creation of new custom apps directly from the Shopify admin. Stores that were already using a custom-app token before that date can continue to use it. For all new setups, prefer the Client Credentials method above.
Connection fields
In addition to the Common connection fields above, this method requires:
Admin API access token
Yes
—
The Admin API access token (prefixed shpat_) from your custom app. Stored as a Snowflake secret.
Generate your API Access Token
For stores that still have access to the legacy admin-side custom-app flow:
In your Shopify admin, go to Settings → Apps and sales channels → Develop apps.
Click Allow custom app development if prompted (on both screens).
Click Create an app, give it a name, then click Create App.
Open the Configuration tab, and under Admin API Integration click Configure.
Choose the access scopes you need. We recommend enabling read (and write, if you're using outbound) access for all the Shopify objects you intend to sync. The next section breaks down the minimum scopes per stream if you'd prefer to grant least-privilege access.
A missing scope for a single field will cause the whole stream to fail mid-sync, so err on the side of including a scope rather than excluding it.
Scopes for inbound syncs
customers\
read_customers (mandatory)
products\
read_products (mandatory)
read_publications (for
availablePublicationsCountfield)
orders\
read_orders (mandatory)
read_customer (for
customerfield)read_products (for
line_items -> variantfield)read_payment_terms (for
paymentTermsfield)
returns (dep. orders)\
all scopes from
ordersread_returns (mandatory)
fulfillments (dep. orders)\
all scopes from
ordersread_fulfillments (mandatory)
read_locations (for
locationfield)
shippingLine (dep. orders)\
all scopes from orders
product_variants\
read_products (mandatory)
read_inventory (for
duplicateSkuCountfield)read_shipping (for
duplicateSkuCountfield)
locations\
read_locations (mandatory)
shopifyPaymentsAccount\
read_shopify_payments_accounts (mandatory)
balanceTransactions\
read_shopify_payments_accounts (mandatory)
payouts\
read_shopify_payments_accounts (mandatory)
shop\
read_products (for
allProductCategoriesListfield)read_locations (for
locationfield)read_markets (for
marketWebPresencefield)read_legal_policies (for
shopPoliciesfield)read_locales (for
alternateLocalesfield)
inventory_items\
read_inventory (mandatory)
inventory_levels (dep. inventory_items)\
read_inventory (mandatory)
read_locations (for
locationsfield)
Scopes for outbound syncs
Customers
write_customers
Products
write_products
Orders
write_orders
Fulfillment
write_fulfilments
Click Save.
At the top right of the page click Install app and complete the installation.
After installation, an Admin API access token (prefixed
shpat_) is generated. Copy it immediately — Shopify only shows it once.
API key vs Admin API access token. Under API Credentials you'll see an API key and an API secret key. These are not the value you paste into Omnata's "Admin API access token" field — that's the shpat_* token shown on installation. The Admin API access token is not viewable again after the first reveal; store it somewhere safe (e.g. a password manager) in case you need to reconfigure the connection later.
Inbound Syncs
All inbound syncs use Shopify's GraphQL Admin API. Each stream's primary key is id and uses a source-defined cursor.
Full Refresh
orders
Shipping line items attached to orders pulled in the current sync window.
Full Refresh
orders
Refund adjustment records attached to orders pulled in the current sync window.
Full Refresh
orders
Fulfillment records attached to orders pulled in the current sync window.
Full Refresh
—
Shopify Payments account details. (Note: the stream is currently named paymens_account — a typo in the source plugin. This is expected to be renamed in a future release.)
ShopifyQL Analytics
The plugin exposes four inbound streams that surface storefront analytics from Shopify's ShopifyQL engine:
analytics_hourly
One row per hour
Incremental
analytics_daily
One row per day
Incremental
analytics_weekly
One row per week
Incremental
analytics_monthly
One row per month
Incremental
These streams use ShopifyQL rather than the Admin GraphQL API. The numbers come directly from Shopify's own storefront analytics engine, so they match what you see in the Shopify Analytics dashboard.
Each granularity is a separate stream (and therefore a separate Snowflake table). Sync just one (e.g. analytics_daily for BI dashboards) or all four for finer-grained drill-downs.
On the first sync the plugin walks back 365 days of history. Subsequent runs resume from the stored cursor (latest_period_end).
Columns
All four streams share the same schema. Each row represents one time bucket at the chosen granularity.
Identifiers
id
string
No
Synthetic primary key: {granularity}_{period_start}
period_start
string
No
Start of the time bucket
Session metrics
sessions
integer
Yes
Number of online store visits
online_store_visitors
integer
Yes
Unique visitors
conversion_rate
number
Yes
Visits that resulted in a sale (decimal ratio)
bounce_rate
number
Yes
Visits that ended after a single pageview (decimal ratio)
average_session_duration
number
Yes
Average visit duration in seconds
pageviews
integer
Yes
Total pageviews across all visits
added_to_cart_rate
number
Yes
Visits with items added to cart (decimal ratio)
reached_checkout_rate
number
Yes
Visits that reached checkout (decimal ratio)
sessions_with_cart_additions
integer
Yes
Visits in which a visitor added an item to cart
sessions_that_completed_checkout
integer
Yes
Visits in which a purchase was completed
Sales metrics
total_sales_from_new_customers
number
Yes
Total sales amount from new customers
total_sales_from_returning_customers
number
Yes
Total sales amount from returning customers
Currency: Sales columns report in the shop's base currency. The stream does not include a currency column. If you sync multiple stores, join to the shop stream (which includes currency metadata) or standardise currency in a downstream model.
Rate columns land as decimal ratios (0.0 - 1.0), not percentages (0 - 100). All metric columns are nullable -- ShopifyQL returns null for periods with no traffic.
How dependent streams work
Streams marked as depending on another (e.g. order_returns depends on orders) are only populated for parent records that appear in the same sync. This means a Full Refresh of order_returns returns only the returns for orders fetched in that sync — pair it with a Full Refresh of orders if you need complete coverage.
Bulk vs basic GraphQL operations
The plugin uses Shopify's GraphQL bulk operations for large streams and falls back to standard paginated GraphQL when the volume is below a threshold (currently 500 records). The behaviour per stream is:
Basic only
locations, shop, payments_account, balance_transactions, payouts
Always uses the standard paginated GraphQL API.
Bulk only
orders, inventory_items
Always uses the bulk operations API. If a tenant-wide bulk operation is already in progress, the plugin waits for it to finish before submitting its own.
Basic + bulk
customers, products
Uses bulk when the result set is above the threshold; falls back to basic GraphQL otherwise.
Dependent
order_returns, order_shipping_lines, order_refund_adjustments, order_fulfillments, order_fulfillment_line_items, inventory_levels
Populated as a by-product of the parent stream's bulk operation — no independent API calls.
Handling Deletes
Shopify doesn't expose a general change-feed for hard-deleted records on most resources — once an object is deleted, it simply stops appearing in subsequent API responses. The Omnata Shopify plugin does not actively reconcile deletes during incremental syncs.
Outbound Syncs
Supported Outbound sync strategies: Create, Update, Upsert, Delete.
You should structure your source data as described in Outbound sync data structures.
The following streams for these objects are supported:
Create - Creates a new customer.
Update - Updates an existing customer's information.
Upsert - Creates a new customer or updates an existing customer's information.
Delete - Deletes an existing customer.
Existing customers cannot be deleted if they have a pending order.
Create - Creates a new product.
Update - Updates an existing product's information.
Upsert - Creates a new product or updates an existing product's information.
Delete - Deletes an existing product.
Create - Creates an order.
Update - Updates an existing order's information.
Upsert - Creates an order or updates an existing order's information.
Delete - Deletes an existing order.
Create - Fulfills an existing unfulfilled order.
Update - Updates an existing fulfillment's information.
Upsert - Fulfills an existing unfulfilled order or updates an existing fulfillment's information.
Delete - Cancels an already fulfilled order.
Create - Creates a product variant from on a product.
Update - Updates the product variant information.
Upsert - Creates a product variant if it does not exist or updates an existing's product variant's information.
Delete - Deletes a product variant from a product.
Create - Creates an inventory level at a specified location with the location id.
Update - Updates the inventory level stock amount.
Upsert - Creates an inventory level at a specified location with the location id or update the inventory level stock amount if the inventory level does not exist.
Delete - Deletes the entire inventory level.
Inventory levels cannot be deleted if this is the last remaining inventory level of the product variant.
Managing performance
API rate limits per plan
The User Tier you select on the connection determines the per-second and per-minute REST request rate limits Omnata applies for the plugin. These values are aligned to Shopify's published API rate limits:
Basic
2
40
Shopify
2
40
Advanced
4
40
Shopify Plus
20
400
Enterprise
40
400
If you upgrade or downgrade your Shopify plan, update the User Tier on the connection accordingly so Omnata throttles correctly.
Bulk operations
Shopify has an API feature called bulk operations that offer much higher throughput than standard GraphQL queries. The Omnata plugin attempts to use these where possible to speed up sync times, falling back to regular queries where they cannot be executed.
For streams and target objects that support both modes, the plugin attempts bulk operations:
For inbound syncs, for each stream, if the expected record count for this sync is at or above
inbound_bulk_threshold(default 500).For outbound syncs, for each target objects, when the number of records in the sync run is at or above
outbound_bulk_threshold(default 50).If below, it fall back to paginated GraphQL queries
Concurrency
Shopify allows a limited number of bulk operations per shop at a time.
If bulk operations are already in flight (started either by Omnata or by another integration), the plugin will wait for it to finish before submitting another. The maximum wait is 1 hour, after which the plugin falls back to the basic paginated API for streams that support both modes.
Contention with other integrations - If another app on the same Shopify store is also running bulk operations, Omnata will see the same "already in progress" responses and follow the same wait-then-fallback behaviour. On busy shops you may see basic + bulk streams fall back to paginated GraphQL more often during peak periods.
Disable bulk operations
You can force paginated GraphQL on a basic + bulk stream by setting the non_bulk_override sync parameter to true. This applies regardless of record count. Bulk-only streams (orders, inventory_items) ignore it.
Last updated