Twitter's API was paywalled in early 2023 — the free tier was eliminated and Basic access costs $100/month. Pulse reads X's own public pages from a residential IP and returns engagement data as clean JSON with one GET request. No API key, no OAuth, no monthly fee to start.
curl "https://pulse.walls.sh/metrics?url=https://x.com/naval/status/1002103360646823936"
{
"platform": "x",
"views": null,
"likes": 273333,
"comments": 11103,
"shares": 78861,
"quotes": 13002,
"bookmarks": 202736,
"publishedAt": "2018-05-31T08:23:54.000Z",
"title": "How to Get Rich (without getting lucky):",
"author": "@naval"
}
Those are live numbers. Pulse returns likes,
comments, shares, quotes, bookmarks,
publishedAt, title, and author for any public post.
views is available for posts after October 2022 (when X added view counts);
older posts return null for views.
# These resolve to the same post curl "https://pulse.walls.sh/metrics?url=https://x.com/naval/status/1002103360646823936" curl "https://pulse.walls.sh/metrics?url=https://twitter.com/naval/status/1002103360646823936"
Pass either domain — Pulse normalises them to the same canonical post.
curl "https://pulse.walls.sh/profile?url=https://x.com/naval"
{
"platform": "x",
"handle": "naval",
"followers": 3419316,
"following": 0,
"posts": 27048,
"verified": true
}
Profile URLs return follower count, following count, post count, and verified status for any public X account.
JavaScript / Node
const tweetUrl = "https://x.com/naval/status/1002103360646823936";
const res = await fetch(
"https://pulse.walls.sh/metrics?url=" + encodeURIComponent(tweetUrl)
);
const { likes, comments, shares, quotes, bookmarks, publishedAt } = await res.json();
console.log({ likes, comments, shares, quotes, bookmarks, publishedAt });
Python
import requests
tweet_url = "https://x.com/naval/status/1002103360646823936"
data = requests.get(
"https://pulse.walls.sh/metrics",
params={"url": tweet_url}
).json()
print(data["likes"], data["comments"], data["shares"])
GET /metrics/batch?url=X_URL_A&url=X_URL_B&url=X_URL_C
Up to 50 X post URLs per batch request, order preserved. You can mix X with
YouTube, TikTok, Bluesky, Mastodon, and Instagram URLs in the same batch — same endpoint,
same response shape. A deleted or private post returns { url, error:
"content_unavailable" } without failing the rest.
curl "https://pulse.walls.sh/metrics/batch?url=X_URL_1&url=X_URL_2"
# → { "count": 2, "results": [ { "likes": …, "shares": … }, { "likes": …, "shares": … } ] }
Every /metrics call saves a timestamped snapshot. After the
second fetch, /history returns the full series plus computed growth stats:
curl "https://pulse.walls.sh/history?url=https://x.com/naval/status/1002103360646823936"
# → {
# "points": [ { "t": "…", "likes": 273200, … }, … ],
# "latest": { "likes": 273333, "shares": 78861 },
# "delta": { "hours_elapsed": 12.5, "likes": 133, "shares": 12 },
# "velocity": { "likes_per_hour": 10.64, "shares_per_hour": 0.96 }
# }
Add &since=<ISO-timestamp> to fetch only new points since
your last poll. The velocity field answers "is this post still gaining traction?"
without you computing the slope yourself.
Free: 120 calls/minute, no account or signup needed. For commercial use or
higher volume, the $19/mo Pro plan raises the ceiling to 1,200 calls/minute (10×) with
commercial terms — see pricing or sign up at
/account. All endpoints set RateLimit-*
response headers so your code can self-throttle before hitting a 429.
More: full API docs · OpenAPI spec · all supported platforms · YouTube metrics without an API key · TikTok metrics without an API.