Twitter (X) Tweet Metadata — API Fields Reference
The Twitter (X) tweet object returned by APIs is a rich structured record — dozens of fields covering the tweet's content, engagement, entities, geolocation, threading, and context. Devs building on the API need to know what's available without digging through docs.x.com endpoint by endpoint.
This page is the practical fields reference — actual response shape, what each field means, when it's populated vs null. Pricing references URL-cited.
The core fields — always populated
id: string, unique tweet identifier. Persistent across the tweet's lifetime.
text: string, the actual tweet content. Up to 280 characters for standard posts.
author_id: string, ID of the posting account. Combine with /twitter/user/info for full profile data.
created_at: ISO-8601 timestamp. UTC.
conversation_id: string, the root tweet ID of the thread this belongs to. Same as id for standalone tweets.
lang: string, language code (ISO 639-1) — the platform's automated language detection.
public_metrics — the engagement scoreboard
Populated when you request the public_metrics field or use twitterapi.io's default response (includes public_metrics by default).
like_count: int, number of likes.
retweet_count: int, number of retweets.
reply_count: int, number of replies.
quote_count: int, number of quote-tweets.
bookmark_count (X official only): int, added by X in 2023, may be null on older data.
entities — the parsed content
Contains extracted structured entities from the tweet text.
hashtags: list of {start, end, tag} objects. tag is the hashtag without the # prefix.
mentions: list of {start, end, username, id} objects for @ mentions.
urls: list of {start, end, url, expanded_url, display_url, title, description} for URLs. expanded_url is the target after t.co redirect.
cashtags: list of {start, end, tag} for stock cashtags like $TSLA.
annotations (X official): entity-recognition results (people, places, products) — Twitter's NER pass on the text.
referenced_tweets — the threading + amplification pointers
Present when the tweet is a reply, quote, or retweet.
type: string, one of "replied_to", "quoted", "retweeted".
id: string, the referenced tweet's ID.
For a reply: type="replied_to", id = parent tweet.
For a quote tweet: type="quoted", id = quoted tweet.
For a retweet: type="retweeted", id = original tweet.
attachments — media + polls
media_keys: list of media key strings. Use with media_fields expansion for full media metadata (dimensions, URLs, alt text).
poll_ids: list of poll ID strings. Use with poll_fields expansion for poll options + vote counts.
geo — location data
Present when the tweet was posted with location tagging (opt-in per user).
place_id: X place identifier.
coordinates: {type: "Point", coordinates: [lon, lat]} for tweets with precise coordinates.
Most tweets don't have geo populated — location-tagging is opt-in and uncommon.
Runnable — parsing the full metadata
Fetch a tweet + inspect every populated field:
import os, requests, json
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def inspect_tweet(tweet_id: str):
r = requests.get(
f"{BASE}/twitter/tweet",
headers=HEADERS, params={"tweet_id": tweet_id}, timeout=10,
)
r.raise_for_status()
tweet = r.json()
print("Core fields:")
for k in ["id", "created_at", "conversation_id", "lang", "author"]:
print(f" {k}: {tweet.get(k, 'not set')}")
pm = tweet.get("public_metrics", {})
print("public_metrics:", json.dumps(pm, indent=2))
entities = tweet.get("entities", {})
print("entities:")
for k in ["hashtags", "mentions", "urls", "cashtags"]:
vals = entities.get(k, [])
print(f" {k}: {len(vals)} found")
print("referenced_tweets:", tweet.get("referenced_tweets", "none"))
return tweet
inspect_tweet("1234567890")Field-availability matrix — twitterapi.io vs X official
Both providers return the same tweet object structure — differences are in defaults + tier gating.
Two practical observations: (a) non_public_metrics (impressions, profile clicks) is only accessible for the tweet's owner via OAuth user-context — no third-party API can see it; (b) twitterapi.io's default response includes what X official gates behind explicit field requests, which simplifies dev-side handling; per-tweet cost ratio ~33× at $0.00015 vs $0.005 per cited pricing.
Common metadata workflows
Content classification / analysis: use text + lang + entities for NLP pipelines. entities.hashtags for topic mapping, entities.urls for external-reference tracking.
Engagement analysis: public_metrics across a tweet corpus. Compute engagement-rate = (like_count + retweet_count + reply_count) / follower_count from author profile.
Threading / conversation trace: conversation_id + referenced_tweets reconstruct the reply chain. Query all tweets with matching conversation_id for the full thread.
Deletion detection: periodically re-query stored tweet IDs. 404 responses indicate deletion.
Deduplication of retweets: filter on referenced_tweets[].type == "retweeted" and dedupe by the referenced ID to get only original posts.
# Practical example: build a per-tweet metadata table for analysis.
import os, requests, json
from pathlib import Path
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def extract_metadata(tweet: dict) -> dict:
entities = tweet.get("entities", {})
pm = tweet.get("public_metrics", {})
refs = tweet.get("referenced_tweets", [])
return {
"id": tweet.get("id"),
"created_at": tweet.get("created_at"),
"lang": tweet.get("lang"),
"text_length": len(tweet.get("text", "")),
"hashtag_count": len(entities.get("hashtags", [])),
"url_count": len(entities.get("urls", [])),
"mention_count": len(entities.get("mentions", [])),
"is_reply": any(r.get("type") == "replied_to" for r in refs),
"is_quote": any(r.get("type") == "quoted" for r in refs),
"is_retweet": any(r.get("type") == "retweeted" for r in refs),
"like_count": pm.get("like_count", 0),
"retweet_count": pm.get("retweet_count", 0),
"reply_count": pm.get("reply_count", 0),
"has_media": bool(tweet.get("attachments", {}).get("media_keys")),
"has_poll": bool(tweet.get("attachments", {}).get("poll_ids")),
}
# Search query returning multiple tweets → extract metadata → write to JSONL for analysis
r = requests.get(
f"{BASE}/twitter/tweet/advanced_search",
headers=HEADERS,
params={"query": '"machine learning" min_faves:100 lang:en'},
timeout=15,
)
r.raise_for_status()
out = Path("metadata.jsonl")
with open(out, "w") as f:
for tweet in r.json().get("tweets", []):
meta = extract_metadata(tweet)
f.write(json.dumps(meta) + "\n")
print(f"wrote {out} with metadata rows")
# Cost per twitterapi.io/pricing:
# ~500 tweets × $0.00015 = $0.075 per full search
# All 20+ metadata fields included — no extra cost per fieldQuestions readers ask
Do all tweets have geo data?
No — geo-tagging is opt-in per user and most users don't enable it. Most tweets have geo absent or null.
What's the difference between public_metrics and non_public_metrics?
public_metrics is visible to everyone via the API (likes, retweets, replies, quotes). non_public_metrics (impressions, profile clicks, URL clicks) is only accessible for the tweet's owner via OAuth user-context — no third-party API can see it for other users' tweets.
How do I get media URLs from an attachment?
The media_keys field returns keys; use the media_fields expansion or a separate /media endpoint to resolve to full media URLs, dimensions, alt-text. twitterapi.io simplifies this by including media details in the default response.
Can I get the tweet's URL from the metadata?
Not returned as a field, but constructible: https://x.com/. Combine author.userName with id to build the URL client-side.
Why do some fields sometimes return as null?
Field-specific reasons: entities is empty when the tweet has no hashtags/URLs/mentions; referenced_tweets is empty when not a reply/quote/retweet; geo is null when the poster didn't opt into location tagging. Null is a legitimate state, not an error.
Does twitterapi.io return additional fields not in X official's schema?
Response shape closely mirrors X's canonical schema for compatibility. Some helpful conveniences (e.g., media URLs inlined by default) but no exotic non-standard fields — portability across providers is preserved.
Continue
- Twitter (X) API — cluster hub
- Twitter (X) advanced search — complete guide
- Twitter (X) data collection API developer guide
- Twitter (X) analysis API developer guide
- twitterapi.io pricing
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API key