Imported documents not showing without token, but manually created ones work

13 replies
Last updated: Dec 29, 2020
We have about 13,000 documents - most of which we have imported manually using the sanity cli.
For some reason none of these are showing up on our site without using a token. What's odd is that when I manually create a new document, it shows up just fine. I
have checked several imported documents to see they meet the required fields and are published - but to no avail.
I have no idea why imported documents are not showing, but newly created ones are.
AI Update

Based on your description, this is almost certainly a perspective issue related to how your imported documents were created. Here's what's likely happening:

When you import documents via the Sanity CLI, they're typically created as draft documents with IDs prefixed by drafts. (like drafts.post-123). Even though these documents appear as "published" in the Studio, they may not have corresponding published versions (without the drafts. prefix) in your Content Lake.

Meanwhile, when you manually create documents in the Studio and publish them, Sanity properly creates both the draft version AND the published version, which is why those show up on your site.

Why This Matters

As of API version 2025-02-19, the default perspective changed from raw to published. This means:

  • Without a token (production): Your API queries use the published perspective by default, which only returns documents without the drafts. prefix
  • With a token (authenticated): You can access different perspectives including raw (all documents) or previewDrafts (drafts + published)

How to Fix This

You need to "publish" your imported documents so they exist as published versions. Here are your options:

Option 1: Bulk publish via CLI script

Create a script that publishes all your imported documents:

import {createClient} from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  token: 'your-token-with-write-access',
  apiVersion: '2025-02-19',
  useCdn: false
})

// Fetch all draft documents
client.fetch('*[_id in path("drafts.**")]').then(drafts => {
  const transaction = client.transaction()
  
  drafts.forEach(draft => {
    const publishedId = draft._id.replace('drafts.', '')
    const publishedDoc = {...draft, _id: publishedId}
    delete publishedDoc._rev // Remove revision to avoid conflicts
    transaction.createOrReplace(publishedDoc)
  })
  
  return transaction.commit()
})

Option 2: Modify your import script

When importing, create both draft AND published versions:

// For each document you import:
const publishedDoc = {_id: 'my-doc-id', ...data}
const draftDoc = {_id: 'drafts.my-doc-id', ...data}

await client.createOrReplace(publishedDoc)
await client.createOrReplace(draftDoc)

Option 3: Use the Studio UI

If you have a manageable subset, you can open each document in the Studio and click "Publish" to create the published version.

Verify the Fix

After publishing, verify by querying without a token:

// This should now return your documents
fetch('https://your-project.api.sanity.io/v2025-02-19/data/query/production?query=*[_type=="yourType"]')

The key insight is that "published" in Sanity means the document exists without the drafts. prefix, not just that it has a published status flag. Your import process likely only created the draft versions, which is why they only show up when you use a token (which gives you access to the raw or previewDrafts perspectives).

Show original thread
13 replies
Unfortunately we're realising this just a few days before the content team are taking over to update content before a big launch.
• The dataset is public• I've made sure the documents meet validation requirements
• I've made sure documents are published (even toggled on and off)
• They DO show when using a token so I don't think it has anything to do with my groq queries
When you export your dataset, can you see any differences between the documents you originally imported and the new ones you created manually?
Also, if you reimport, do the documents you had created manually no longer appear?
Are there any dots
.
in the imported document ids? Documents on a path will always be private https://www.sanity.io/docs/ids#paths-fdc25ada5db2
Ah yes a lot of them (not all) have dots, like
post.some-id-here
author.some-id-here

This is because I read somewhere in the Sanity docs that using this will allow for some more interesting grow queries.
user J
Considering how many documents we have, can you think of an affordable solution to this?
Changing each one will drive up our quota a lot.
Yes, it's a bit of a hidden footgun that paths are always private. Sorry about that.
Running a script that strips off that path in the ids should be fairly straight forward. You can do multiple (hundreds) of mutations in a single transactions. I'll see if I can dig out an example for you..
I think the "easiest" solution for you would be to use the CLI to1. export the dataset
sanity dataset export
2. modify the data locally (strip off the paths) using a script or search and replace
3. import the dataset
sanity dataset import
to a new name4. update the studio and front-end to use this new dataset
(since document ids are immutable using a script to mutate would be a bit more involved)
Thank you! Just to clarify though, as they would have different id's - reimporting then wouldn't replace the previous document. That's why I need a new dataset?
Yes, that's why I thought having a new dataset would be the best solution. Otherwise you would have to delete all the "old" documents.
Also, I just realised.. are there any references to the documents on paths? If so you will have to update all the references as well with the updated ids
Fortunately not many of them are referenced, and those that are will be caught by the editors.
Thanks a lot
user J

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?