How Nitter Parses GraphQL Tweet Types: Handling TweetUnavailable, TweetTombstone, and Visibility Results
Nitter discriminates GraphQL tweet variants through the parseGraphTweet procedure in src/parser.nim, routing TweetUnavailable, TweetTombstone, and TweetWithVisibilityResults through specialized branches based on the js.getTypeName field while falling back to legacy parsing for standard content.
Nitter, the privacy-focused alternative Twitter frontend, consumes Twitter’s modern GraphQL API to fetch timeline data. Because Twitter represents deleted, restricted, and subscriber-only content through distinct JSON schemas, understanding how Nitter parses GraphQL tweet types is essential for developers extending or debugging the Nim-based scraper.
The Dispatch Logic in parseGraphTweet
The entry point for all GraphQL tweet processing is the parseGraphTweet procedure located in src/parser.nim. According to the source code, this function inspects the incoming JSON node’s type metadata via js.getTypeName and dispatches to dedicated handling logic using a discriminated case statement.
At lines 71–78 of src/parser.nim, the parser checks for special GraphQL tweet types before attempting heavy-weight legacy parsing. This early-exit pattern keeps the parser lightweight for edge-case tweets while preserving full feature support for ordinary content.
Handling Unavailable Content
When Twitter returns metadata indicating a tweet cannot be displayed, Nitter handles two distinct GraphQL representations: TweetUnavailable and TweetTombstone.
TweetUnavailable Nodes
If js.getTypeName returns "TweetUnavailable", the parser immediately returns a default Tweet object with the available field set to false. This indicates the tweet is inaccessible due to network issues, authentication requirements, or geographic restrictions, bypassing all media and card parsing to save resources.
TweetTombstone Nodes
For "TweetTombstone" types—representing content removed due to DMCA requests or Terms of Service violations—the parser extracts the human-readable explanation using the getTombstone helper.
Located in src/parserutils.nim at lines 165–168, getTombstone reads the "text" field from the tombstone node and strips the trailing “Learn more” suffix to normalize the message. The resulting string is placed into the Tweet object’s text field, allowing Nitter to display the removal rationale to users.
Visibility Variants and Recursion
Beyond unavailable content, Twitter’s GraphQL API wraps certain tweets in visibility envelopes that require recursive parsing.
TweetWithVisibilityResults
When encountering "TweetWithVisibilityResults", the parser recursively calls parseGraphTweet on the nested "tweet" object (js{"tweet"}). This unwraps the visibility metadata while preserving the underlying tweet content, ensuring subscriber-only or filtered tweets still render correctly when accessible.
TweetPreviewDisplay
For "TweetPreviewDisplay" types, which represent subscriber-only content viewed by non-subscribers, the parser returns a static message explaining the limited visibility. This prevents parsing errors while clearly communicating the content restriction to the frontend.
Fallback to Legacy Parsing
If the JSON node does not match any of the special GraphQL types listed above, execution falls through to the standard legacy tweet parsing logic within parseGraphTweet. This branch handles traditional tweet structures containing legacy fields, card data, media entities, and user information, ensuring backward compatibility with older API response formats.
Working with the Parser API
The following examples demonstrate how to leverage Nitter’s public parser API to handle GraphQL tweet variants directly.
Parsing a GraphQL Tweet Node
import json, parser
let gqlPayload = readFile("sample_graphql.json")
let js = parseJson(gqlPayload)
# parseGraphTweet returns a fully-populated Tweet record.
let tweet = parseGraphTweet(js)
echo tweet.text # Contains tombstone message, unavailable placeholder, or real text.
echo tweet.available # false for unavailable/tombstone tweets.
Extracting Tombstone Text Manually
import json, parserutils
proc formatTweet(js: JsonNode): string =
case js.getTypeName:
of "TweetTombstone":
# Re-use the library’s helper for consistency.
result = js{"tombstone"}.getTombstone
else:
result = js{"legacy", "full_text"}.getStr
echo formatTweet(someJsonNode)
These snippets illustrate how parseGraphTweet abstracts the complexity of TweetTombstone and TweetUnavailable handling, returning clean Tweet objects regardless of the underlying GraphQL structure.
Summary
- Nitter routes GraphQL tweet variants through
parseGraphTweetinsrc/parser.nim, which discriminates onjs.getTypeNameat lines 71–78. - TweetUnavailable produces a
Tweetwithavailable = false, skipping expensive parsing. - TweetTombstone extracts cleaned removal text via
getTombstoneinsrc/parserutils.nim(lines 165–168), stripping the “Learn more” suffix. - TweetWithVisibilityResults triggers recursive parsing of the nested
"tweet"object to unwrap visibility envelopes. - Unmatched types fall through to legacy parsing, ensuring compatibility with standard tweet structures.
Frequently Asked Questions
What is the difference between TweetUnavailable and TweetTombstone in Nitter?
TweetUnavailable indicates the tweet is simply inaccessible—often due to network errors or geographic blocks—and returns an empty Tweet with available = false. TweetTombstone specifically indicates the tweet was removed by Twitter (e.g., for copyright violations) and contains a text explanation extracted by the getTombstone helper that Nitter displays to the user.
How does Nitter handle subscriber-only tweets in GraphQL responses?
When the parser encounters TweetPreviewDisplay or TweetWithVisibilityResults types, it either returns a static subscriber-only message or recursively parses the nested tweet object, respectively. This ensures the application handles restricted content gracefully without crashing on unexpected JSON schemas.
Where is the tombstone text cleaned in the Nitter codebase?
The getTombstone procedure in src/parserutils.nim (lines 165–168) handles normalization by reading the tombstone node’s "text" field and programmatically removing the trailing “Learn more” suffix that Twitter appends to removal notices.
What happens when Nitter encounters an unknown GraphQL tweet type?
If parseGraphTweet does not recognize the type name from js.getTypeName, execution falls through to the legacy parsing branch. This branch expects standard Twitter API structures containing legacy fields and extracts media, cards, and user data using the traditional parsing logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →