Discussion about filtering out draft articles in Sanity.io API query

18 replies
Last updated: Mar 8, 2022
Hi team, why this is not filter out draft articles https://*******.api.sanity.io/v1/data/query/pre-prod?query=*[_type=='article' && !(_id in path('drafts.*'))]
AI Update

The issue you're experiencing is likely due to the API perspective you're using. Your query *[_type=='article' && !(_id in path('drafts.*'))] is correctly written to filter out drafts, but it might not be working as expected because of how Sanity's API handles perspectives.

The Problem

As of the recent API changes (v2025-02-19), the default perspective for API queries is now published, which means you shouldn't be seeing drafts at all by default. However, if you're explicitly using the previewDrafts perspective or have authentication credentials in your query, the API will automatically return drafts instead of published documents when both exist.

The Solution

You have a few options:

1. Use the published perspective explicitly

Add the perspective parameter to your API URL:

https://*******.api.sanity.io/v1/data/query/pre-prod?query=*[_type=='article']&perspective=published

When using the published perspective, you don't need the draft filter at all - the API will only return published documents automatically.

2. If you need the previewDrafts perspective but want to exclude drafts

Your filter syntax needs a small adjustment. Try using path('drafts.**') (with double asterisks):

*[_type=='article' && !(_id in path('drafts.**'))]

3. Alternative draft filtering approach

You can also filter by checking if the _id starts with "drafts.":

*[_type=='article' && !(_id match 'drafts.*')]

Why This Matters

The draft documents system in Sanity stores drafts and published versions as separate documents. When you use previewDrafts perspective (common in preview environments), Sanity intelligently returns the draft version when it exists, otherwise falling back to the published version. This is great for previews but can be confusing when you explicitly want to exclude drafts.

The most reliable approach is to use the perspective=published parameter, which ensures you only get published content without needing any draft filtering in your query.

It's currently looking for something that exactly matches
drafts.
Does it work if you change it to
!(_id in path('drafts.**'))
? Also, it looks like you're using
v1
of the API. You may also want to change over to a more recent version .
without url encoding
once url encoded, I will get a result but draft articles also included in the result
drafts not filter out from above URL as well, updated api version and used this filter !(_id in path('drafts.**'))
Where are you running this query? If you run it in Vision do you get the correct results? I can't verify it since you've blocked out your document id.
Where are you running this query? If you run it in Vision do you get the correct results? I can't verify it since you've block out your document id.
Thank you very much Racheal, I'll test this on vison and let you know.
by default is it send two article objects if article is in draft status
What do you get if you run the query with the snippet I gave:
*[_type == 'article' && !(_id in path('drafts.**'))]
. Again, also make sure that you're not using v1 of the API in Vision.
I got it πŸ™‚. once you create a article and if you never published it, then it has only a draft id. when you filter out articles from this !(_id in path('drafts.**')) those never published articles will get filtered but articles which are published at first then edited by someone won't get filtered.
Thank you very much for your quick response and guidance 😊
Happy to help! It's always fun to see folks have this start to click for them!
Hi
user M
is there a way of filter out both draft and previous state from the article list if article has a draft version.
I want to remove both 1 and 5 due to 'content test' article has a it's draft version. and I just want to select only 0, 2, 3, 4 from this article list.
Hey Dineth! You'd use the same method for excluding drafts that we worked through yesterday. As soon as edits are made to a published document, the
_id
will have the
drafts.
prepended to it again.
yes, got it. thank you Racheal πŸ™Œ
You're welcome!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?