Tracking events associated with the "Product" update

We’re trying to track all changes made to a product using Shopify’s GraphQL Admin API, particularly through the Product object. We found the events connection and initially thought it would be useful for understanding what changes happened to a product over time.

However, we’ve noticed a couple of issues:

  1. Inventory updates (changes to inventory levels or restocks) are not captured in the events object.
  2. Even some product-level updates (e.g., changes to metafields, product options, or variant details) don’t always trigger a new event in the events list.

This makes it difficult to maintain a reliable audit trail or understand exactly what changed in a product and when in the update.

Ideally, we would love to have a consistent log of product-related changes — especially inventory and variant-level changes — accessible via GraphQL or through another API.

Is the recommended approach still to rely on webhooks and maintain a separate change log externally?

Appreciate any insight or workarounds others have found.

1 Like

Hey @Chinmay_Sharma!

As you noticed, the events connection captures some product updates, but not the comprehensive audit trail you are looking for.

For inventory specifically, you can use the inventoryHistoryUrl field when querying inventory items through the Admin GraphQL API. While the history is not available via API, this provides a link to the inventory history section in the admin (InventoryItem - GraphQL Admin).

The most reliable approach remains setting up webhooks to track various product-related events.

Thanks for your response, but unfortunately, that won’t help much in my case.

To explain the issue in more detail: we’re currently using the updatedAt field on the Product object to fetch product updates. This field gets updated not only when there are actual changes to the product itself (like title, tags, metafields, etc.), but also when inventory levels for any of the variants change.

The challenge here is that we want to determine what exactly was updated so that we can decide whether or not to take action on that update. Right now, every time the updatedAt timestamp changes, our system treats it as a product update — but without knowing whether it was an actual product change or just an inventory adjustment, we can’t make an informed decision.

Since the events object doesn’t capture inventory changes and often misses updates to variant-level fields, there’s no clear way for us to distinguish between meaningful product updates and inventory-only changes.

Our goal is to be able to track changes accurately — either through an audit trail, field-level change tracking, or reliable metadata — so we can process only the updates that matter to us.

Would love to hear if there’s a more recommended way to accomplish this.

Hey @Chinmay_Sharma

Thanks for that extra context. Have you checked to see if filters would work for you? You could set this up to only trigger on the events that are meaningful to you.

At the moment, we’re not using the webhook-based approach. Instead, we’ve transitioned from REST APIs to GraphQL and are relying entirely on the GraphQL Admin API.

Given that, is there any recommended way — using GraphQL alone — to identify what specifically changed in a product (e.g., inventory vs. actual product data) without needing to upgrade or significantly modify our current infrastructure?

We’d prefer to stick with our GraphQL-based setup if possible, so any guidance on how to approach this within that context would be greatly appreciated.

Hey @Chinmay_Sharma,

What information are you getting through REST to show you the specific changes on a product that you aren’t getting with Graphql?

We’ve recently migrated from REST to the GraphQL Admin API for product handling. Previously, while using REST, we had a system that would fetch product updates and re-index them accordingly — even though we couldn’t track the exact changes in each update, the system was stable and performed well.

However, after migrating to GraphQL and updating our framework that handles product creation and updates, we’ve noticed performance issues. Specifically, the system is now going down when trying to re-index products on every single update, using the same infrastructure and machine as before.

Because of this, we’re now trying to be more selective — we want to trigger indexing only when there are meaningful updates to a product (such as actual changes to product attributes, not just inventory changes). The challenge is that the updatedAt timestamp on the Product object also gets updated when variant inventory changes, making it difficult to determine the nature of the change.

We’re hoping to find a GraphQL-based solution to help us differentiate between inventory-only updates and actual product data changes — ideally without having to rebuild our infrastructure or switch to webhooks at this point.

Thanks for clarifying that. Would it work to include the inventoryLevels.updatedAt timestamp in your query? This way, if the product update and the inventorylevel match, you know the update is related specifically to the inventory adjustment.

For example:

query Product {
    product(id: "gid://shopify/Product/8011698569238") {
        id
        title
        updatedAt
        variants(first: 10) {
            nodes {
                inventoryItem {
                    inventoryLevels(first: 10) {
                        nodes {
                            updatedAt
                        }
                    }
                }
            }
        }
    }
}

I did consider filtering updates using the updatedAt field on the Product object, but there’s a challenge we’re running into.

Our system pulls product updates from Shopify on a scheduled basis — for example, every hour or every 3 hours. The problem is that if a product has an actual update (like a change in title, tags, or options) but also has frequent inventory changes afterward, the updatedAt field reflects only the most recent update, which could be inventory-related.

As a result, the actual product update gets buried behind subsequent inventory updates, and our system misses it entirely.

Thanks for sharing that. Good point on the most recent updates. Webhooks with filters do seem like the most reliable trigger for monitoring changes. Since that’s not going to be feesible at this time, using an updatedAt filter query and then comparing the important product fields from the previous request to the new request to identify the non-inventory changes might be the next best option.