How to Extract Text from Claude Code JSON Stream Output

2026-01-09 01:55 (2 months ago)
Newline Thief
Play a song themed on this article

Background / Problem

When you use Claude Code’s --output-format=stream-json option, you get streaming output in JSON Lines format like this:

{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"容を"}},...}
{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"レビューして"}},...}
{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"問"}},...}

From this stream, you want to extract only the text content in the .event.delta.text field and display it in real time in the terminal.

Requirements

  • Output the text fragments continuously (no newline per fragment)
  • Only print a newline when \n appears in the text
  • Support real-time streaming

Attempt 1: The problem with jq -r

The first method tried:

claude code ... | jq -r '.event.delta.text? // empty'

Issues:

  • The -r (--raw-output) option appends a newline after each output result
  • Fragments like “容を”, “レビューして”, “問” end up each on their own line
  • As a result, text that should be continuous gets broken up unnaturally

Solution: The jq -j option

Final solution:

claude code の ${HOME}/.claude/local/claude \
  --verbose --permission-mode delegate \
  --print --output-format=stream-json --include-partial-messages "/push-with-review" \
  | jq -j '.event.delta.text? // empty'

Characteristics of jq -j (--join-output)

  • Does not automatically add newlines when printing output
  • Concatenates text as-is
  • Any \n inside the text is displayed as an actual newline
  • Ideal for streaming processing

When you need to handle multiple message types

| jq -j '
  (.event.delta.text? // empty),
  (.message.content[]?.text? // empty)
'

This lets you continuously output text from both stream_event and assistant messages.

jq filter details

jq features used

  1. Optional operator (?)

    • Using .event.delta.text? prevents errors even if the field doesn’t exist
  2. Alternative operator (//)

    • // empty outputs nothing when the value is null or undefined
  3. Strict filtering with select() (alternative)

    | jq -j 'select(.event.delta.text != null) | .event.delta.text'
    

Reference

jq option comparison

Option Behavior Use case
-r (--raw-output) Adds a newline after each result When you want to process line by line
-j (--join-output) Does not add newlines When you want continuous text output
-c (--compact-output) Compresses JSON into one line Keep JSON structure while compacting

Reference URLs

Conclusion

To extract only the text from Claude Code’s streaming output, jq’s -j option is the best fit.

  • Simple
  • Fast
  • Works with real-time streaming
  • No need to build a dedicated tool in Rust, etc.

Practical examples

# Basic form
claude -p "タスク内容" | jq -j '.event.delta.text? // empty'

# Filter only stream_event
claude -p "タスク内容" | jq -j 'select(.type == "stream_event") | .event.delta.text? // empty'

With this, you can display Claude Code output in a human-readable format in real time.

Please rate this article
Currently unrated
The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Categories

Archive