No simple way to check variant Online Store publication

With variant-level publishing in Admin API 2026-07, how should an app efficiently determine whether a specific variant is published on the Online Store?

ProductVariant.publishedOnPublication requires the shop-specific Online Store publication ID. Apps must therefore discover that ID and repeatedly query it or cache it per shop.

product.publishedAt is insufficient because the product can be published while the variant is not. availableForSale also isn’t equivalent to publication state.

Could Shopify add ProductVariant.publishedOnOnlineStore or variant-level publishedInContext? Requiring every app to manage opaque publication IDs seems excessive for such a basic visibility check.

Hey @Angelina_Prokopeva - I had a look into this for you!

In 2026-07 the ProductVariant picks up the Publishable interface, and there’s no dedicated publishedOnOnlineStore or variant-level publishedInContext field, so you’re correct that publishedOnPublication(publicationId:) is the supported per-variant check. You’re also right that product.publishedAt and availableForSale answer different questions, the latter being “can a buyer purchase this on the storefront” rather than “is it published to this channel”.

Playing around on my test store, the publication ID part was less painful than it looks because that ID is stable per shop. The one gotcha is matching, since publication.name is deprecated and catalog.title comes back as an auto-generated string like “Channel Catalog … for Online Store”. Match on the channel handle online_store instead, which is stable and not localized:

query {
  publications(first: 50, catalogType: APP) {
    edges { node { id channels(first: 1) { nodes { handle name } } } }
  }
}

If you’d rather skip the cached ID entirely, resourcePublicationsV2 on the variant gives you the full set of channels in one call, and you can pick out the Online Store entry by that same handle. The variant-level publishing guide covers the 2026-07 behavior and recommends reading variant publication state through that field.

A first-class variant-level “published on Online Store” field is absolutely reasonable feedback, so I’ve passed it along to the relevant team internally as a feature request - thanks for raising this here!

Thank you very much for detailed explanations.

Honestly, it’s pretty complicated in comparison to the interface the product object provides. Especially if we need to do pagination to extract all Publications.

If we can ask a couple more questions, that would be very helpful to understand the best implementation. If using the same approach to identify if a variant is published on B2B catalog publication based on buyer context:

  1. how many B2B catalogs can be assigned to one company location? Can we rely that there are 25 B2B catalogs that can be assigned to one company location, as it’s described here?

  2. how Market catalogs can be resolved for one shipping address?

  3. is the publication ID for the online store channel persistent for a store? Or it could change?

Thank you in advance.

Hi @Donal-Shopify sorry to ping you again here. I just wanted to follow up on my last reply in this thread whenever you have a chance

Hey @Angelina_Prokopeva, I don’t get to check the forums as often as I’d like so I do appreciate your patience here!

On B2B catalogs per company location, yes, you can rely on 25 as the documented maximum assignable to a single company location, and that counts both direct assignments and catalogs inherited through B2B markets. Rather than assuming the cap, though, read the actual assignments straight off the location. CompanyLocation exposes catalogs and catalogsCount, so you can list the catalogs in scope, grab each catalog’s publication, and run publishedOnPublication(publicationId:) per variant against those.

In relation to resolving Market catalogs for a shipping address, there isn’t a single Admin API call that takes an address and you the catalog. The chain is country/region to Market to that market’s catalog (catalogType: MARKET) to its publication. A market catalog only exposes a publication when it customizes product availability, so a pricing-only catalog hands you a price list and a null publication. If your goal is “what does this specific buyer actually see,” the path is to let the storefront resolve it for you with the Storefront API @inContext(country:) directive, which returns only what’s published and available in the matched market.

For the Online Store publication ID, it’s persistent per shop and won’t rotate under normal conditions, so discovering it once and caching it per shop is fine. Just keep matching on the channel handle online_store rather than the catalog title, since that handle is the stable, non-localized identifier.

Hope this helps!

Thanks @Donal-Shopify your insights are very helpful!

I really hope Shopify will also release a publishedInContext endpoint for variant-level resolution to close the gap.

Regarding publication status on Markets catalogs, I found that marketsResolvedValues could potentially be used to retrieve all market-level Publication IDs based on the country code. From there, we can use the same publishedOnPublication(publicationId:) endpoint to determine the publication statuses.
One question I still have: how many market catalogs can be assigned to a single country? Since the assignment is country-based, we could ultimately resolve the relevant catalog for a company location through its country code. However, if multiple market catalogs can be assigned to the same country, we would need to understand how Shopify determines which catalog applies.

P.S. We cannot use the Storefront API because it requires adding a Customer Account authorization redirect just to obtain a customerAccessToken. That would be too disruptive for our current flow. Our app was designed around the Admin API before the latest release that introduced variant-level publications.

@Donal-Shopify I also was experimenting with CompanyLocation.catalogs endpoint is it does NOT return catalogs inherited through B2B markets. Here was the set up:

The endpoint returned empty catalogs, even though there is “B2B market catalog” in the B2B market assigned.

Could you please take a look if it is expected behavior or my test setup was incorrect.

Thanks in advance!