npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-x-embed

v1.0.1

Published

Embed X (Twitter) posts in React — link previews, responsive media, and payload validation. No API key required.

Readme

react-x-embed

Embed X (Twitter) posts in React. No API key, no iframe, no client-side JavaScript required.

A fork of vercel/react-tweet that fixes the outstanding crashes, matches X's own embed layout, and renders the data the syndication API returns but upstream ignored.

pnpm add react-x-embed
import { Tweet } from 'react-x-embed'

export default function Page() {
  return <Tweet id="1628832338187636740" />
}

Fully compatible with React Server Components — tweets render statically, so nothing ships to the client.

Why this fork

Every change below is anchored to a real payload. The repo ships eight captured syndication responses plus X's own rendered HTML, CSS, and computed geometry for each, so layout decisions are measured against X rather than guessed at.

Crashes fixed

  • Videos with no mp4 rendition. getMp4Video returned undefined and the player dereferenced .url on it. Those tweets took down the page.
  • Malformed payloads. A deleted or suspended account returns a tweet-shaped object with no user, which threw Cannot read properties of undefined (reading 'screen_name') on the first property access. Responses are now validated before rendering and degrade to the "not found" state. (#135, #144, #197)

Bugs fixed

  • Video in Safari (#191) — X ships an HLS rendition alongside the mp4s, and Safari plays it far more reliably than X's mp4 endpoints, which don't always honour byte-range requests. It's now offered as a <source>, listed first so Safari prefers it.
  • AbortError on play (#213) — the click handler resolved the video through previousSibling, but hiding the play button re-renders the subtree and could detach that node before play() settled. Now resolved through a ref.
  • Portrait media dominating the embed (#159) — a 9:16 video rendered at 177.8% padding, nearly twice as tall as the embed is wide. Capped at 100%, matching X.
  • Blurry and missing avatars (#201) — the API only reports the 48×48 _normal rendition, which is soft on retina and the one X purges most aggressively. Upgraded to _400x400.
  • Infinite loading stateuseTweet reported isLoading: true forever when given no id, since SWR never fetches without a key. Common with ids from routes that haven't resolved.
  • Build failure in React Router / Vite (#206) — Rollup resolves export * through a 'use client' module inconsistently and reported useTweet as missing. Now re-exported by name.
  • Touch targets below WCAG minimum (#173) — the author name, handle and Follow link rendered 20px tall against WCAG 2.2's 24px floor. Measured in Chrome: three failures before, zero after, with no visual change.
  • Unoverridable container styles (#192) — margin and max-width tied on specificity with consumer utility classes, so source order decided, and consumer CSS usually loads first. Both moved to :where() for zero specificity.

Added

  • Link preview cards. The syndication API returns a fully populated card for any tweet sharing a link — title, description, domain, and up to seven image renditions. Upstream rendered none of it. This was the largest visible gap against X's own embeds.
  • Responsive images. A srcset built from the renditions X advertises, instead of always requesting the 680px one.
  • Colour placeholders. The dominant colour X computed for each image fills its box while it loads, rather than flashing empty.
  • Withheld media handling. DMCA takedowns and region blocks still appear in the payload but 404 on fetch; they're filtered instead of rendering broken.
  • Video quality selection. getMp4Video(media, 'low' | 'medium' | 'high') instead of a hardcoded rendition.

Documentation

Full docs live in apps/site. Start with the introduction, then the guide for your framework:

Caching

Rendering a tweet calls X's syndication API. Getting rate limited is hard but possible, particularly if you rely on the default SWR endpoint — it's a shared service this project doesn't operate. Before production, set up caching and your own API route.

What this cannot do

The syndication API is the only endpoint that works without credentials, and it returns exactly one tweet at a time. Timelines, user profiles, search, threads, and reposts are not reachable — every other endpoint is either credential-gated or returns nothing. A repost also resolves to the original tweet, so it cannot be distinguished from it.

Engagement data is limited to favorite_count and conversation_count. There is no retweet, reply, quote, bookmark, or view count on the tweet itself.

Contributing

See the contributing docs. Tests run against captured fixtures, so pnpm test needs no network access.

License

MIT. Originally created by Luis Alvarez at Vercel; see license.md.