
Configuring Shopify as a Source
In the Sources tab, click on the “Add source” button located on the top right of your screen. Then, select the Shopify option from the list of connectors. Click Next and you’ll be prompted to add your access.1. Add account access
You’ll need a Shopify Admin API access token and your store identifier.- Access Token: The private app access token for authenticating API requests.
- Store ID: The name of your Shopify store extracted from your store admin URL. Use only the store subdomain:
https://[store].myshopify.com/admin→Store ID = [store]. - Start Date: The earliest record date to sync.
How to create a Custom App and generate an Access Token
How to create a Custom App and generate an Access Token
Access the Dev Dashboard
- Log in to your Shopify store admin at
https://[your-store].myshopify.com/admin - Go to Settings > Apps
- Click Develop apps
- Click Build apps in Dev Dashboard to open the Dev Dashboard
Create a new Custom App
- In the Dev Dashboard, click Create app
- In the “Start from Dev Dashboard” section, enter a name for your app (e.g., “Nekt Data Integration”)
- Click Create
Configure your app version
- In the URLs section:
- Set your App URL to
https://shopify.dev/apps/default-app-home - Add
https://developers.google.com/oauthplaygroundas an Allowed redirection URL
- Set your App URL to
- Select a Webhooks API Version (use the latest stable version)
- In the Access section, enter the following scopes:
- Click Release
- Optionally enter a version name (e.g., “v1.0”) and message
- Click Release to confirm
Get your Client Credentials
- In the Dev Dashboard, go to your app’s Settings page
- Copy your Client ID and Client Secret
Open the Google OAuth Playground
Configure the OAuth Playground
- Replace
SHOP_NAMEwith your store’s subdomain in both:- OAuth authorization endpoint:
https://[your-store].myshopify.com/admin/oauth/authorize - OAuth token endpoint:
https://[your-store].myshopify.com/admin/oauth/access_token
- OAuth authorization endpoint:
- Replace
SHOPIFY_CLIENT_IDwith your Client ID - Replace
SHOPIFY_CLIENT_SECRETwith your Client Secret - Click Close
Authorize and Get Your Access Token
- Click Authorize APIs (Step 1 in the playground)
- You’ll be redirected to Shopify - click Install app to grant permissions
- After returning to the playground, click Exchange authorization code for tokens (Step 2)
- Your access token will appear in the response on the right side
Managing Legacy Custom Apps (created before January 2026)
Managing Legacy Custom Apps (created before January 2026)
Access Legacy Apps
- Go to Settings > Apps in your Shopify admin
- Find your app in the Legacy custom apps section
- Click on the app to manage its settings
View or Regenerate Access Token
- Go to the API credentials tab
- Click Reveal token once to view your access token
- Copy the token immediately - it’s only shown once
- If you need a new token, uninstall and reinstall the app
2. Select streams
Choose which data streams you want to sync — you can select all streams or pick specific ones that matter most to you. For faster extractions, select only the streams relevant to your analysis.Tip: The stream can be found more easily by typing its name.Select the streams and click Next.
3. Configure data streams
Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.- Layer: Choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
- Folder: A folder can be created inside the selected layer to group all tables being created from this new data source.
- Table name: We suggest a name, but feel free to customize it. You have the option to add a prefix to all tables at once and make this process faster!
- Sync Type: You can choose between INCREMENTAL and FULL_TABLE.
- Incremental: Every time the extraction happens, we’ll get only the new data — which is good if, for example, you want to keep every record ever fetched.
- Full table: Every time the extraction happens, we’ll get the current state of the data — which is good if, for example, you don’t want to have deleted data in your catalog.
4. Configure data source
Describe your data source for easy identification within your organization, not exceeding 140 characters. To define your Trigger, consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times). Optionally, you can determine when to execute a full sync. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while. Once you are ready, click Next to finalize the setup.5. Check your new source
You can view your new source on the Sources page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.Streams and Fields
Below you’ll find all available data streams from Shopify and their corresponding fields:Orders
Orders
updatedAt.Key Fields:id- Unique identifier for the ordername- The order name (e.g., #1001)legacyResourceId- Legacy numeric IDemail,phone- Contact informationprocessedAt,createdAt,updatedAt,cancelledAt,closedAt- Timestampsconfirmed- Whether the order is confirmedcurrencyCode,presentmentCurrencyCode- Currency codes
transactions[].id,kind,status,gateway,authorizationCode,test,paymentIdtransactions[].createdAt,processedAttransactions[].amountSet.presentmentMoney.amount,currencyCodetransactions[].amountSet.shopMoney.amount,currencyCodetransactions[].parentTransaction.id
totalPriceSet- Total price (shopMoney + presentmentMoney)subtotalPriceSet- Subtotal pricetotalShippingPriceSet- Total shippingtotalDiscountsSet- Total discountstotalTaxSet- Total taxtotalWeight,taxesIncluded,taxExempt
displayFinancialStatus- Financial status (PAID, PENDING, REFUNDED, etc.)displayFulfillmentStatus- Fulfillment status (FULFILLED, UNFULFILLED, PARTIAL, etc.)fullyPaid,fulfillable,restockable,test,customerAcceptsMarketingsourceName,sourceIdentifier,currentSubtotalLineItemsQuantitytags,note,clientIp
customer.id,firstName,lastName,emailshippingAddress.*- Full shipping addressbillingAddress.*- Full billing address
discountCode,discountCodes[]metafields[].id,namespace,key,value,type,description,createdAt,updatedAt
channelInformation.channelDefinition.handle
lineItems[].id,title,quantity,sku,vendor,variantTitlelineItems[].customAttributes[].key,valuelineItems[].discountedTotalSet.*,originalTotalSet.*lineItems[].discountAllocations[].allocatedAmount.amount,currencyCodelineItems[].discountAllocations[].discountApplication.targetType,allocationMethod,targetSelection,title,description,codelineItems[].variant.id,title,sku,product.id,product.title
Products
Products
updatedAt.Key Fields:id- Unique product identifiertitle- Product titledescriptionHtml- HTML descriptionvendor- Vendor nameproductType- Product type/categoryhandle- URL-friendly slugcreatedAt,updatedAt,publishedAt- Timestampsstatus- Product status (ACTIVE, ARCHIVED, DRAFT)tags- Product tagstemplateSuffix- Liquid template suffix
options[].id,name,position,values[]
variants[].id,title,sku,price,positionvariants[].inventoryPolicy- Inventory policy (DENY, CONTINUE)variants[].compareAtPrice- Original price before discountvariants[].createdAt,updatedAt,taxable,barcodevariants[].inventoryItem.id- Link to inventory item
images[].id,altText,originalSrcfeaturedImage.id,altText,originalSrc
metafields[].id,namespace,key,value,type,description
Inventory Items
Inventory Items
updatedAt.Key Fields:id- Unique inventory item IDlegacyResourceId- Legacy numeric IDsku- Stock keeping unittracked- Whether inventory is trackedtrackedEditable.reason- Why tracked field is editablerequiresShipping- Whether item requires shippingduplicateSkuCount- Count of duplicate SKUsinventoryHistoryUrl- URL to inventory historycreatedAt,updatedAt- Timestamps
countryCodeOfOrigin,provinceCodeOfOriginharmonizedSystemCodecountryHarmonizedSystemCodes[].countryCode,harmonizedSystemCode
inventoryLevels[].id- Inventory level IDinventoryLevels[].location.id,location.name- Location infoinventoryLevels[].item.id,item.sku- Item infoinventoryLevels[].quantities[].id,name,quantity,updatedAt- Quantity by type (available, committed, incoming, etc.)
unitCost.amount,unitCost.currencyCodemeasurement.weight.unit,measurement.weight.valuelocationsCount.count
variant.id,variant.title,variant.skuvariant.product.id,variant.product.title
Customers
Customers
updatedAt.Key Fields:id- Unique customer IDfirstName,lastNamecreatedAt,updatedAtverifiedEmail,taxExempt,tags,statenumberOfOrders- Total order count
amountSpent.amount,amountSpent.currencyCodedefaultEmailAddress.emailAddress,defaultEmailAddress.marketingStatedefaultPhoneNumber.phoneNumber,defaultPhoneNumber.marketingState,defaultPhoneNumber.marketingCollectedFrom
addresses[].id,firstName,lastName,address1,city,province,country,zip,phone,name,provinceCode,countryCodeV2defaultAddress.*- Same structure as addresses
metafields[].id,namespace,key,value,type,description
Collections
Collections
updatedAt.Key Fields:id,title,handle,descriptionpublishedAt,updatedAt
image.altText,image.originalSrc
products[].id,title,handle,createdAt,updatedAtproducts[].productType,vendor,tags,totalInventory,status,price,inventoryQuantityproducts[].variants[].id,title,sku,price,inventoryQuantity
sortOrder,sortType,sortValue,templateSuffix,url
metafields[].id,namespace,key,value,type,description
Locations
Locations
id,nameactive,activatable,deactivatable,deletablecreatedAt,updatedAt,deactivatedAtaddressVerified,isFulfillmentService
fulfillmentService.id,fulfillmentService.serviceName
address.address1,address2,city,country,countryCode,province,provinceCode,zip
metafields[].id,namespace,key,value,type,description
Abandoned Checkouts
Abandoned Checkouts
id- Unique identifier for the abandoned checkoutabandonedCheckoutUrl- URL for the abandoned checkoutcreatedAt,updatedAt,completedAt- TimestampstaxesIncluded- Whether taxes are included
subtotalPriceSet.presentmentMoney.amount,currencyCodetotalPriceSet.presentmentMoney.amount,currencyCodetotalTaxSet.presentmentMoney.amount,currencyCodetotalDiscountSet.presentmentMoney.amount,currencyCode
customer.id,firstName,lastName,email,tags,state,note,createdAt,updatedAt
billingAddress.*- Address lines, city, province, country, zip, phoneshippingAddress.*- Address lines, city, province, country, zip, phone
lineItems[].id,title,sku,quantitylineItems[].variant.id,variant.price
discountCodes[]taxLines[].rate,title,priceSet.presentmentMoney.amount,currencyCode
ShopifyQL Reports
In addition to the standard streams above, the Shopify connector supports ShopifyQL Reports — custom analytics queries written in ShopifyQL, Shopify’s analytics query language. This allows you to extract aggregated metrics directly from Shopify’s analytics engine, such as sales breakdowns, traffic data, and product performance reports. Each ShopifyQL report you configure becomes its own data stream with a dynamically discovered schema based on the query’s result columns.How to configure ShopifyQL Reports
ShopifyQL Reports are configured as an advanced setting when setting up the Shopify source.read_reports scope to be able to use ShopifyQL Reports.Open Advanced Settings
Add a report
- Report name: A unique identifier for the report (letters, numbers, and underscores only). This becomes part of the stream name — for example, a report named
daily_salesproduces a stream calledreport_daily_sales. - ShopifyQL query: The full ShopifyQL query to execute. The query must be valid ShopifyQL syntax.
SINCE -30d), the results will reflect the most recent window each time it runs.ShopifyQL query examples
Below are ready-to-use ShopifyQL queries you can paste directly into the report configuration. Each example includes the recommended Report name and the Query to use.Daily Sales Summary
Daily Sales Summary
daily_salesQuery:| Column | Type | Description |
|---|---|---|
day | String | Date (YYYY-MM-DD) |
gross_sales | String | Gross sales amount |
discounts | String | Total discounts applied |
returns | String | Total returns amount |
net_sales | String | Net sales (gross - discounts - returns) |
shipping | String | Shipping charges |
taxes | String | Tax amount |
total_sales | String | Total sales (net + shipping + taxes) |
Monthly Sales Summary
Monthly Sales Summary
monthly_salesQuery:| Column | Type | Description |
|---|---|---|
month | String | Month (YYYY-MM) |
gross_sales | String | Gross sales amount |
discounts | String | Total discounts applied |
returns | String | Total returns amount |
net_sales | String | Net sales |
shipping | String | Shipping charges |
taxes | String | Tax amount |
total_sales | String | Total sales |
orders | String | Number of orders |
Sales by Product
Sales by Product
sales_by_productQuery:| Column | Type | Description |
|---|---|---|
product_title | String | Product name |
product_type | String | Product type/category |
gross_sales | String | Gross sales for this product |
net_sales | String | Net sales for this product |
orders | String | Number of orders containing this product |
total_sales | String | Total sales including shipping and taxes |
Sales by Traffic Referrer
Sales by Traffic Referrer
sales_by_referrerQuery:| Column | Type | Description |
|---|---|---|
referrer_name | String | Referrer name (e.g., Google, Facebook) |
referrer_source | String | Referrer source type |
gross_sales | String | Gross sales from this referrer |
net_sales | String | Net sales from this referrer |
orders | String | Number of orders from this referrer |
Sales by Billing Country
Sales by Billing Country
sales_by_countryQuery:| Column | Type | Description |
|---|---|---|
billing_country | String | Customer billing country |
gross_sales | String | Gross sales from this country |
net_sales | String | Net sales from this country |
orders | String | Number of orders from this country |
total_sales | String | Total sales from this country |
Sales by Discount Code
Sales by Discount Code
sales_by_discountQuery:| Column | Type | Description |
|---|---|---|
discount_code | String | Discount code used |
gross_sales | String | Gross sales with this discount |
discounts | String | Total discount amount applied |
net_sales | String | Net sales after discount |
orders | String | Number of orders using this discount |
Daily Orders and Average Order Value
Daily Orders and Average Order Value
daily_ordersQuery:| Column | Type | Description |
|---|---|---|
day | String | Date (YYYY-MM-DD) |
orders | String | Number of orders |
gross_sales | String | Gross sales amount |
net_sales | String | Net sales amount |
average_order_value | String | Average order value |
Working with ShopifyQL data
All ShopifyQL report columns are returned as String type, regardless of their original data type (money, number, percentage, etc.). Cast them to the appropriate types when querying in your Lakehouse:- AWS
- GCP
Data Model
The following diagram illustrates the relationships between the core data streams in Shopify.Use Cases for Data Analysis
This guide outlines valuable business intelligence use cases focused on inventory intelligence, helping you optimize stock levels, identify sales velocity, and prevent lost revenue from stockouts or overstocking. Run these queries on Explorer.1. Inventory Health Dashboard
Get a comprehensive view of your inventory health by product, including stock levels, cost valuation, and risk classification across all locations. Business Value:- Identify products at risk of stockouts before they happen
- Spot overstocked items tying up capital
- Understand inventory distribution across locations
SQL query
SQL query
- AWS
- GCP
Sample Result
Sample Result
| product_title | sku | variant_title | available_qty | committed_qty | incoming_qty | total_incoming_available | location_count | inventory_value | currency | stock_status |
|---|---|---|---|---|---|---|---|---|---|---|
| Classic White Tee | CWT-S | Small | 0 | 3 | 50 | 50 | 2 | 0.00 | USD | OUT_OF_STOCK |
| Denim Jacket | DJ-M | Medium | 2 | 8 | 0 | 2 | 1 | 89.98 | USD | LOW_STOCK |
| Canvas Sneakers | CS-42 | EU 42 | 4 | 1 | 20 | 24 | 3 | 159.96 | USD | LOW_STOCK |
| Leather Belt | LB-L | Large | 15 | 2 | 0 | 15 | 2 | 224.85 | USD | NORMAL |
| Summer Dress | SD-M | Medium | 47 | 5 | 0 | 47 | 2 | 1,551.00 | USD | HEALTHY |
| Basic Socks Pack | BSP-OS | One Size | 342 | 12 | 200 | 542 | 3 | 1,710.00 | USD | OVERSTOCK |
| Status | SKU Count | % of Catalog | Action |
|---|---|---|---|
| Healthy | 112 | 45% | No action needed |
| Normal | 62 | 25% | Monitor regularly |
| Low Stock | 38 | 15% | Plan reorder |
| Out of Stock | 20 | 8% | Urgent reorder |
| Overstock | 18 | 7% | Consider markdowns |
2. Sales Velocity & Days of Stock Remaining
Combine order data with inventory levels to understand how fast each product sells and estimate days of stock remaining — the core metric for preventing stockouts. Business Value:- Forecast when products will run out of stock
- Prioritize reordering based on sales velocity
- Identify fast-moving products that need safety stock buffers
SQL query
SQL query
- AWS
- GCP
Sample Result
Sample Result
| product_title | sku | units_sold_30d | orders_30d | revenue_30d | daily_velocity | available_qty | days_of_stock | reorder_urgency |
|---|---|---|---|---|---|---|---|---|
| Classic White Tee | CWT-S | 89 | 76 | 2,225.00 | 2.97 | 0 | 0 | STOCKOUT |
| Denim Jacket | DJ-M | 42 | 38 | 3,318.00 | 1.40 | 2 | 1 | CRITICAL |
| Canvas Sneakers | CS-42 | 35 | 30 | 2,794.65 | 1.17 | 4 | 3 | CRITICAL |
| Leather Belt | LB-L | 28 | 25 | 839.72 | 0.93 | 15 | 16 | MONITOR |
| Summer Dress | SD-M | 18 | 15 | 1,079.82 | 0.60 | 47 | 78 | HEALTHY |
| Urgency | SKU Count | Avg Days of Stock | Revenue at Risk (30d) |
|---|---|---|---|
| STOCKOUT | 3 | 0 | $6,750.00 |
| CRITICAL (< 7 days) | 5 | 3 | $8,420.00 |
| REORDER NOW (7-14 days) | 8 | 11 | $4,230.00 |
| MONITOR (14-30 days) | 12 | 22 | $3,100.00 |
| HEALTHY (> 30 days) | 72 | 65 | — |
3. Inventory Distribution by Location
Analyze how your inventory is distributed across fulfillment locations to optimize warehouse allocation and reduce shipping times. Business Value:- Balance inventory across warehouses to reduce shipping costs
- Identify locations running low on key products
- Optimize fulfillment routing
SQL query
SQL query
- AWS
- GCP
Sample Result
Sample Result
| location_name | unique_skus | total_available | total_committed | total_inventory_value | out_of_stock_skus | low_stock_skus | stockout_rate_pct |
|---|---|---|---|---|---|---|---|
| Main Warehouse - NYC | 248 | 12,450 | 892 | 187,250.00 | 8 | 14 | 3.2 |
| West Coast Fulfillment - LA | 195 | 8,320 | 645 | 124,800.00 | 12 | 22 | 6.2 |
| Pop-Up Store - Miami | 86 | 1,240 | 78 | 18,600.00 | 5 | 18 | 5.8 |
| Location | Inventory Value Share | Available Units Share | Stockout Rate |
|---|---|---|---|
| Main Warehouse - NYC | 56.6% | 56.5% | 3.2% |
| West Coast Fulfillment - LA | 37.7% | 37.8% | 6.2% |
| Pop-Up Store - Miami | 5.6% | 5.6% | 5.8% |
4. Inventory Turnover & Dead Stock Analysis
Identify products that aren’t selling (dead stock) versus those with healthy turnover, helping you make markdown, promotion, or discontinuation decisions. Business Value:- Free up capital tied in dead stock through markdowns
- Identify candidates for clearance sales or bundles
- Optimize purchasing decisions based on actual turnover rates
SQL query
SQL query
- AWS
- GCP
Sample Result
Sample Result
| product_title | sku | units_sold_90d | revenue_90d | available_qty | stock_value_at_cost | annual_turnover_rate | turnover_category |
|---|---|---|---|---|---|---|---|
| Vintage Scarf | VS-BLU | 0 | 0.00 | 85 | 1,275.00 | Dead Stock | |
| Wool Gloves | WG-M | 3 | 89.97 | 67 | 670.00 | 0.18 | Slow Mover |
| Leather Belt | LB-L | 28 | 839.72 | 15 | 224.85 | 7.47 | Moderate |
| Classic White Tee | CWT-M | 156 | 3,900.00 | 22 | 220.00 | 28.36 | Fast Mover |
| Canvas Sneakers | CS-42 | 35 | 2,794.65 | 4 | 159.96 | 35.00 | Fast Mover |
| Turnover Category | SKU Count | Stock Value ($) | % of Total Value | Recommended Action |
|---|---|---|---|---|
| Fast Movers (6x+/yr) | 24 | 12,400.00 | 15% | Increase safety stock |
| Moderate (2-6x/yr) | 48 | 24,800.00 | 30% | Maintain current levels |
| Slow Movers (< 2x/yr) | 35 | 20,650.00 | 25% | Reduce reorder quantities |
| Dead Stock (0 sales) | 18 | 24,750.00 | 30% | Markdown / bundle / discontinue |
5. Abandoned Cart Recovery Intelligence
Analyze abandoned checkout data to understand lost revenue potential and identify high-value recovery opportunities. Business Value:- Quantify revenue lost from abandoned carts
- Identify the most abandoned products to address pricing or UX issues
- Prioritize recovery campaigns by cart value
SQL query
SQL query
- AWS
- GCP
Sample Result
Sample Result
| abandon_date | total_abandoned | recovered | recovery_rate_pct | total_cart_value | lost_revenue | recovered_revenue | avg_cart_value | avg_items_per_cart |
|---|---|---|---|---|---|---|---|---|
| 2026-01-27 | 34 | 6 | 17.6 | 4,892.50 | 4,032.00 | 860.50 | 143.90 | 2.4 |
| 2026-01-26 | 41 | 8 | 19.5 | 5,740.80 | 4,618.30 | 1,122.50 | 140.02 | 2.1 |
| 2026-01-25 | 28 | 4 | 14.3 | 3,980.20 | 3,410.00 | 570.20 | 142.15 | 2.6 |
| 2026-01-24 | 52 | 11 | 21.2 | 7,280.00 | 5,726.40 | 1,553.60 | 140.00 | 2.3 |
| 2026-01-23 | 38 | 7 | 18.4 | 5,320.60 | 4,342.10 | 978.50 | 140.02 | 2.2 |
| Metric | Value |
|---|---|
| Total Abandoned Carts | 193 |
| Total Cart Value | $27,214.10 |
| Lost Revenue | $22,128.80 |
| Recovered Revenue | $5,085.30 |
| Average Recovery Rate | 18.6% |
| Average Cart Value | $141.01 |
Implementation Notes
GraphQL API
- This connector uses the Shopify Admin GraphQL API for efficient data extraction
- All monetary values are returned as strings (e.g.,
"29.99") — cast them to numeric types in your queries - The connector uses cursor-based pagination for optimal API performance
ShopifyQL Reports
- ShopifyQL reports use a newer API version (
2026-01) than the standard GraphQL streams (2025-07) - Reports always run as full table syncs (no incremental support)
- The schema is automatically discovered at extraction time by executing the query and reading column metadata
- If a query returns no data, schema discovery will fail — ensure your time range (
SINCE/UNTIL) covers a period with data - ShopifyQL supports querying the
sales,orders,products, andcustomersdata models — refer to the ShopifyQL reference for the full syntax and available fields
Incremental Sync
- Orders, Products, Inventory Items, Customers, and Collections support incremental sync using
updatedAt - Locations, Abandoned Checkouts, and ShopifyQL Reports use full table sync
- Use incremental sync for large stores to minimize API calls and extraction time
Nested Data Structures
- Line items, transactions, variants, metafields, and inventory levels are stored as nested arrays
- Use
UNNEST(GCP) orCROSS JOIN UNNEST(AWS) to flatten these arrays in your queries - The connector automatically flattens GraphQL connection structures (edges/node) into clean arrays
Inventory Quantities
- The
inventoryLevels[].quantities[]array contains multiple quantity types per location:available— Units available for salecommitted— Units reserved for unfulfilled ordersincoming— Units expected from incoming transferson_hand— Total physical units at the location
- Filter by
nameto get the quantity type you need
Price Sets
- Shopify provides monetary values in both shop currency (your store’s base currency) and presentment currency (the customer’s local currency)
- Use
shopMoneyfor internal reporting andpresentmentMoneyfor customer-facing analysis
API Scopes Required
The Shopify connector requires the following API scopes:read_orders— Orders and transactionsread_products— Products, variants, and collectionsread_customers— Customer profilesread_inventory— Inventory items and levelsread_locations— Store locationsread_reports— ShopifyQL reports