---
title: stories find Examples and Troubleshoot
description: Shows `stories find` examples for common audits and fixes for slow runs and missing results.
url: https://www.storyblok.com/docs/tooling/cli/stories/find/examples
---

# stories find Examples and Troubleshoot

This page includes [`stories find`](/docs/tooling/cli/stories/find) snippets for common audits and maintenance tasks, and lists troubleshooting tips for slow runs, missing results, and rejected flags.

## Examples

The examples assume you defined a `space` in the configuration file and use the flags that need the fewest requests. For details, refer to [content flags](/docs/tooling/cli/stories/find#content-flags).

### Check whether a story is still referenced

List the stories that reference a story before you delete it. `--references` runs on the server, and `--skip-content` skips the per-story fetch. The search needs no story content. An empty result means that no story references the target.

```bash
storyblok stories find --references "0c4f0f4a-9b5e-4c3a-8e7d-2f1a6b8c9d0e" --skip-content | jq --raw-output '.full_slug'
```

### Check whether a block is still in use

Before you remove a block from the schema, list the stories that still use it. `--includes-block` finds the block at any depth on the server. The search runs without a `--where` expression or a per-story fetch. A count of zero means that no story uses the block.

```bash
# List the stories that use a block
storyblok stories find --includes-block legacy_hero --skip-content | jq --raw-output '.full_slug'

# Count the stories that use each of several blocks
for block in legacy_hero old_teaser promo_banner; do
  echo "$block: $(storyblok stories find --includes-block "$block" --skip-content | wc -l)"
done
```

### Audit images without alt text

Find every story in the space with an asset that has a file but no alt text, at any depth. `--capi-filter --skip-content` suits a search that reads content across the whole space: bulk reads supply the content, and no story needs its own fetch. `--entry-type story` excludes folders, which have no bulk content.

```bash
storyblok stories find --entry-type story --capi-filter --skip-content \
  --where '$..[?(@.fieldtype == "asset" && @.filename != null && @.filename != "" && (@.alt == null || @.alt == ""))]' \
  | jq --raw-output '.full_slug' > missing-alt.txt
```

### Audit links and references

Check the references and links in every story. `--capi-filter` reads the content in bulk. For the issue types and the output format, refer to [reference checks](/docs/tooling/cli/stories/find#reference-checks).

```bash
# Save every reference issue in the space as a repair list
storyblok stories find --check-references --capi-filter \
  | jq --compact-output '{slug: .full_slug, issues: [._ref_issues[] | {type, field_path, cached_url, actual_url}]}' \
  > reference-issues.jsonl

# List stories with outdated URLs. For example, after a slug or folder restructure
storyblok stories find --check-references stale_url --capi-filter | jq --raw-output '.full_slug'

# List published stories that reference unpublished targets
storyblok stories find --check-references unpublished --publish-status published | jq --raw-output '.full_slug'
```

### List changes waiting to go live

List stories by publish status, workflow stage, and scheduled publish. The story listing includes the publish status and the workflow stage. These searches need no story content.

```bash
# List published stories with unpublished changes, most recent first
storyblok stories find --publish-status published-with-changes --skip-content --sort updated_at:desc \
  | jq --raw-output '[.full_slug, .updated_at] | @tsv'

# List draft stories, oldest first
storyblok stories find --publish-status draft --skip-content --sort created_at:asc | jq --raw-output '.full_slug'

# List stories at the workflow stage with the ID 42
storyblok stories find --workflow-stage 42 --skip-content | jq --raw-output '.full_slug'

# List stories scheduled to publish in the next two weeks
storyblok stories find --scheduled 2w --skip-content | jq --raw-output '.full_slug'
```

### Find recent and outdated content

Date flags read the story listing. A story outside the range costs no per-story fetch. For the accepted date ranges, refer to [date filters](/docs/tooling/cli/stories/find#date-filters).

```bash
# List the stories updated in the last 24 hours, most recent first
storyblok stories find --updated 1d --skip-content --sort updated_at:desc \
  | jq --raw-output '[.updated_at, .full_slug] | @tsv'

# List published stories that nobody updated in the last year
storyblok stories find --entry-type story --publish-status published --updated ..1y --skip-content \
  | jq --raw-output '.full_slug'

# Count the stories first published in each month of 2025
storyblok stories find --first-published 2025 --skip-content \
  | jq --raw-output '.first_published_at[0:7]' | sort | uniq -c
```

### Build a content inventory

```bash
# Count the stories per content_type
storyblok stories find --skip-content | jq --raw-output '.content_type' | sort | uniq -c | sort -rn

# Count the stories below a path prefix
storyblok stories find --starts-with en/blog --skip-content | wc -l

# Save an inventory as CSV for a spreadsheet
storyblok stories find --skip-content | jq --raw-output '[.id, .full_slug, .content_type, .published] | @csv' > inventory.csv
```

### Check translation coverage

Each [internationalization](/docs/concepts/internationalization) approach shows translation state in a different way, and `--where` covers every approach.

#### Field-level translation

[Field-level translation](/docs/concepts/internationalization#field-level-translation) stores translated values as [`<field>__i18n__<lang>` keys](/docs/api/management/stories/internationalization-for-stories) in `content`. The Content Delivery API drops these keys. Use Management API content for these searches, and omit `--capi-filter`. Narrow the scope with server-side filters such as `--container-block` instead.

```bash
# Find stories with a missing or empty German title
storyblok stories find --where '$[?(!$.content.title__i18n__de || $.content.title__i18n__de == "")]'

# Find stories with an empty German description at any depth
storyblok stories find --container-block product --where '$..[?(@.description__i18n__de == "")]'
```

#### Folder-level translation

[Folder-level translation](/docs/concepts/internationalization#folder-level-translation) stores each language under its own path. Use `--starts-with` to restrict a search to one language.

```bash
# Find German draft stories
storyblok stories find --starts-with "de/" --publish-status draft --skip-content

# Count the published stories per language
for lang in en de fr; do
  echo "$lang: $(storyblok stories find --starts-with "$lang/" --publish-status published --skip-content | wc -l)"
done
```

#### Individual translation publishing

With [individual translation publishing](/docs/concepts/internationalization#set-up-field-level-translation) enabled, each story has a `translated_stories` array with one entry per language. The story listing omits this array. Run these searches without `--skip-content`. They need the per-story fetch, which returns the array.

```bash
# Find stories whose German version was never published
storyblok stories find --where '$.translated_stories[?(@.lang == "de" && @.published_at == null)]'

# Find stories whose French version has unpublished changes
storyblok stories find --where '$.translated_stories[?(@.lang == "fr" && @.unpublished_changes == true)]'
```

#### Per-language workflow stages

With [workflows](/docs/manuals/workflows), the `stages` array holds one entry per language, each with a `workflow_stage_id`. The story listing includes `stages`. These searches work with `--skip-content`. Use `--workflow-stage` to match any language.

```bash
# Find stories with any language at the stage with the ID 42
storyblok stories find --workflow-stage 42 --skip-content

# Find stories whose German version is at the stage with the ID 42
storyblok stories find --skip-content --where '$.stages[?(@.language == "de" && @.workflow_stage_id == 42)]'
```

### Match any or all values

The following patterns match any block or reference, and all tags:

```bash
# Find stories that use either of two blocks, with one search per block
for block in hero hero_v2; do
  storyblok stories find --includes-block "$block" --skip-content
done | jq --slurp --compact-output 'unique_by(.uuid)[]'

# Find stories that reference either of two stories, with one search per UUID
for uuid in 0c4f0f4a-9b5e-4c3a-8e7d-2f1a6b8c9d0e 7a2b3c4d-1e2f-4a5b-9c8d-0e1f2a3b4c5d; do
  storyblok stories find --references "$uuid" --skip-content
done | jq --slurp --compact-output 'unique_by(.uuid)[]'

# Find stories that carry both of two tags: one tag on the server, the other with --where
storyblok stories find --tag campaign --skip-content --where '$.tag_list[?(@ == "legacy")]'
```

`unique_by(.uuid)` removes stories that more than one search returns.

### Process results with other tools

Piped output is [JSON Lines](/docs/tooling/cli/stories/find#piped-output). Line-based tools such as [`jq`](https://jqlang.org/) process it as it arrives.

```bash
# Print slugs, one per line
storyblok stories find --container-block product | jq --raw-output '.full_slug'

# Count the matches
storyblok stories find --container-block product | wc -l

# Save selected fields as JSON Lines
storyblok stories find --container-block product | jq --compact-output '{id, name, component: .content.component}' > products.jsonl

# Save the results as a single JSON array
storyblok stories find --starts-with lp --skip-content | jq --slurp '.' > lp.json
```

`jq --slurp` reads the whole output before it prints anything. Results appear only after the run ends.

### Review results before you write

Save the selection to a file and review the file before you pass it to a command that writes:

```bash
# Save the selection
storyblok stories find --starts-with en/campaigns --updated ..2023 --skip-content > selection.jsonl

# Review the selection
wc -l selection.jsonl
jq --raw-output '.full_slug' selection.jsonl | less
```

Before you write stories that `--check-references` returns, remove the [annotations](/docs/tooling/cli/stories/find#annotations).

## Troubleshoot

The following sections list symptoms of `stories find`, their causes, and fixes. For the flags that these fixes use, refer to [content flags](/docs/tooling/cli/stories/find#content-flags).

### The run is slow

A search that reads `content` fetches every story in scope one at a time, at six requests per second by default. Narrow the scope first, then change how the run gets content:

1.  Move filters from `--where` to server-side flags such as `--starts-with`, `--includes-block`, `--container-block`, `--tag`, and `--publish-status`.
2.  Replace a `--where` expression on a date with `--created`, `--updated`, `--last-published`, or `--first-published`. These flags skip the per-story fetch for stories outside the range.
3.  Run the same flags without `--where`, plus `--skip-content | wc -l`, to count the stories in scope. When the count divided by six comes to minutes, add `--capi-filter`.
4.  Add `--skip-content` when the output needs no `content`.

Fetches every story in the space

```bash
storyblok stories find --where '$..[?(@.component == "hero" && @.headline == "")]'
```

Fetches only the stories that contain a hero block

```bash
storyblok stories find --includes-block hero --where '$..[?(@.component == "hero" && @.headline == "")]'
```

Reads content in bulk and fetches no story one at a time

```bash
storyblok stories find --includes-block hero --capi-filter --skip-content \
  --where '$..[?(@.component == "hero" && @.headline == "")]'
```

To sort or limit results, use `--sort` and `--limit`. A `jq` sort holds back the whole result set before it prints the first line.

### An expression takes too long to test

Add `--limit 5` or pipe into `head -n 5` while you develop an expression. The run stops after the first results, whatever the size of the space.

### A `--where` expression matches nothing

Check the following causes:

-   `--skip-content` with an expression that reads `content`: the story listing has no content. Remove `--skip-content` or add `--capi-filter`.
-   `@` where `$` belongs: `$[?(@.updated_at > "2025-01-01")]` tests each property value of the story. Use `$[?($.updated_at > "2025-01-01")]` to test the story.
-   Shell expansion of part of the expression: wrap the expression in single quotes.

### A search with `--capi-filter --skip-content` misses matching stories

An expression on `content` excludes folders, unpublished stories, and stories in a failed batch. Run the search without `--skip-content`, or add `--entry-type story` to exclude folders. For details, refer to [`--capi-filter`](/docs/tooling/cli/stories/find#--capi-filter).

### The command rejects an `__i18n__` key under `--capi-filter`

The Content Delivery API drops field-level translations. Use `--capi-params language=de` to request the language and match the base field name, or run the search without `--capi-filter`.

### The command rejects `--capi-params version=published`

The Content Delivery API returns a published version only for stories that someone published. Add `--publish-status published`, `--publish-status published-with-changes`, or both.

### A reference check reports no issues for some stories

Run the check without `--capi-filter` to include references in field-level translations and stories without Content Delivery API content. For details, refer to [`--capi-filter`](/docs/tooling/cli/stories/find#--capi-filter).

### A reference check returns too many results

Targets that are drafts report as `unpublished`. A space with many drafts returns many results. Check `broken` first, because those references point to missing stories:

```bash
storyblok stories find --check-references broken
```

Then [list published stories that reference unpublished targets](/docs/tooling/cli/stories/find/examples#audit-links-and-references).

### The command exits with code 1

Part of the run failed, and the results may be incomplete. Check the summary on `stderr` and run the command again. For all codes, refer to [exit codes](/docs/tooling/cli/stories/find#exit-codes).

### The output differs in a terminal and in a script

The command prints a table in a terminal and JSON Lines when you pipe the output. To get JSON Lines in a terminal, pipe the output into `cat`. For details, refer to [output](/docs/tooling/cli/stories/find#output).

## Pagination

-   [Previous: Reference](/docs/tooling/cli/stories/find)
-   [Next: pull](/docs/tooling/cli/stories/pull)
