
If you only want to show a public Twitter profile on a website, you may not need to build a complete API integration. An official embedded timeline is usually enough.
You need the Twitter Timeline API when you want more control over the result. For example, you may want to display only the latest five posts, remove replies, create your own card layout, show media separately, or combine Twitter data with content from other platforms.
The current X API endpoint for retrieving a user’s recent posts is:
GET /2/users/{id}/tweets
The endpoint returns structured JSON rather than ready-made HTML. Your server should request the data, prepare the fields your website needs, and then send a safe response to the browser. The bearer token should never be exposed in front-end JavaScript.
For a multi-platform workflow, you can also compare the available options through KeyAPI’s Twitter API.
There are three practical ways to place Twitter content on a website.
Method | Best for | Development work | Layout control | API credentials |
|---|---|---|---|---|
Official embedded timeline | A simple public profile feed | Low | Limited | Usually not handled by your server |
Direct X API integration | Custom feed and application logic | Medium to high | High | Required |
Unified social media API | Websites that also use other platforms | Medium | High | Managed through the provider |
An embedded timeline is usually the fastest option if your requirement is simply:
Show a public account
Keep the standard Twitter/X appearance
Avoid building a custom data pipeline
Display the feed without storing posts in your database
This approach is suitable for a company website, author page, event page, or documentation site.
The disadvantage is control. You normally cannot treat each post as a normal content object in your own system. Filtering, custom sorting, media processing, and cross-platform reporting are also limited.
The API is a better fit when the website needs to control the output.
Typical examples include:
A developer portal showing product announcements
A news page displaying only posts with images
A campaign page showing posts from a selected account
A dashboard combining Twitter, TikTok, Instagram, and YouTube data
A product page with a custom “latest updates” section
This is the use case covered by this article.
If your website only needs Twitter, a direct X API integration may be enough.
If the same page also needs TikTok videos, Instagram posts, YouTube data, or Threads content, maintaining separate authentication rules and response formats becomes more expensive. A unified provider can reduce the amount of platform-specific code, but you should still check:
Which fields are returned
How often data is refreshed
Whether media URLs are included
How deleted posts are handled
How usage and billing are measured
A reliable Twitter feed normally follows this path:
X API
↓
Your server
↓
Data filtering and normalization
↓
Cache or database
↓
Website frontendThe browser should not call the X API with your private bearer token. If the token is placed in client-side JavaScript, anyone can inspect it through browser developer tools.
A safer structure is:
Website browser → /api/twitter-feed on your server → X APIYour server keeps the credentials private and returns only the fields that the page needs.
The official endpoint requires a numeric X user ID. It does not use the username directly in the URL.
A typical request looks like this:
curl "https://api.twitter.com/2/users/2244994945/tweets?max_results=10&tweet.fields=created_at,public_metrics,attachments&expansions=attachments.media_keys&media.fields=url,preview_image_url,type" \
-H "Authorization: Bearer $BEARER_TOKEN"The official X API reference documents GET /2/users/{id}/tweets and supports tweet fields, expansions, and media fields through query parameters. View the official endpoint reference.
The important point is that the response contains data, not a finished website component.
Field | Why it matters on a website |
|---|---|
| Creates a stable link to the original post |
| Displays the post content |
| Shows publication time |
| Displays likes, replies, reposts, and quotes |
| Connects a post with its media |
| Retrieves image or video metadata |
| Loads older posts when pagination is required |
Do not request every available field by default. Smaller responses are easier to cache, faster to process, and simpler to maintain.
The following Node.js example shows the basic server-side pattern:
import express from "express";
const app = express();
app.get("/api/twitter-feed", async (req, res) => {
try {
const url = new URL(
"https://api.twitter.com/2/users/2244994945/tweets"
);
url.searchParams.set("max_results", "10");
url.searchParams.set(
"tweet.fields",
"created_at,public_metrics,attachments"
);
url.searchParams.set(
"expansions",
"attachments.media_keys"
);
url.searchParams.set(
"media.fields",
"url,preview_image_url,type"
);
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.X_BEARER_TOKEN}`
}
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json({
error: "Twitter timeline request failed"
});
}
res.json({
posts: data.data || [],
media: data.includes?.media || [],
nextToken: data.meta?.next_token || null
});
} catch {
res.status(500).json({
error: "Unable to load Twitter timeline"
});
}
});
app.listen(3000);This example deliberately does not expose the bearer token to the browser.
The front end can then request your own endpoint:
const response = await fetch("/api/twitter-feed");
const feed = await response.json();
feed.posts.forEach((post) => {
console.log(post.text);
});The browser only sees the response created by your server.
A common mistake is sending the complete X API response directly to the page. That makes the front-end code depend too closely on the provider’s response structure.
A better approach is to convert the response into a smaller internal format:
{
"id": "1780000000000000000",
"text": "Example post text",
"publishedAt": "2026-07-28T08:30:00.000Z",
"url": "https://x.com/example/status/1780000000000000000",
"imageUrl": null,
"metrics": {
"likes": 12,
"replies": 3,
"reposts": 5
}
}Your front end then works with your own fields instead of depending on every detail returned by X.
This becomes especially useful if you later replace a direct integration with a unified provider. The page does not need to change as long as the server continues returning the same internal format.
Text-only feeds are simple. Media makes the implementation more complicated.
The post may contain:
An image
Multiple images
A video
A GIF
No media at all
Do not assume that every post has a direct image URL. The post may only contain media keys, while the actual media objects appear under the includes.media section of the response.
Your server should:
Read the post’s media keys.
Match them with the objects in includes.media.
Select the correct URL or preview image.
Return one normalized media object to the front end.
Display a text-only card when no media is available.
Always include a fallback. A feed that shows blank cards when a post has no image looks broken even when the API request succeeded.
A website should not request the timeline from X every time a visitor opens the page.
A practical starting setup is:
Cache the response for 5 to 15 minutes.
Store the last successful response.
Serve the cached response if the new request fails.
Refresh the cache in the background when possible.
Request only the number of posts displayed on the page.
For example, if the website displays five posts, requesting 100 posts on every page view creates unnecessary API usage.
Caching also improves page speed. Visitors receive the latest successful response from your server instead of waiting for a third-party API request.
Error | Likely cause | What to check |
|---|---|---|
| Invalid or missing credentials | Bearer token, header format, environment variable |
| Access or permission problem | Account access, endpoint availability, token permissions |
| User or resource not found | Correct numeric user ID and account status |
| Retired endpoint | Old v1.1 URL or outdated library |
| Rate limit or usage limit | Request volume, plan limits, caching |
Empty | No accessible posts or wrong filters | Account visibility, filters, request parameters |
X’s official troubleshooting documentation lists authentication, endpoint access, request parameters, package limits, and response parsing as common areas to inspect. It also documents 401, 403, 404, 410, and 429 error conditions. Read the official error troubleshooting guide.
If the same request works in cURL or Postman but fails in your application, the problem is probably in your server code, token loading, or response parsing.
Before placing the feed on the homepage, test it with a small acceptance checklist.
Confirm that the numeric user ID resolves to the account you intend to display. Do not rely only on the username stored in a form field.
Use a small response first. Confirm that the feed displays:
Text-only posts
Image posts
Posts with links
Long text
Deleted or unavailable content
Posts with missing metrics
Temporarily use an invalid token and verify that the website:
Does not expose credentials
Shows the cached response or a fallback message
Does not render an empty page
Logs the error on the server
Returns a useful HTTP status
Check that repeated page views use the cache instead of generating a new API request every time. This is one of the easiest ways to reduce unnecessary usage.
The API is not automatically the right answer.
Use an official embedded timeline when the requirement is only to show a standard public profile feed.
Use the API when you need custom cards, filtering, media processing, your own caching, or data from multiple accounts.
Use a unified social media API when the page needs Twitter alongside several other platforms and the team wants one normalized data layer.
The right choice depends less on the word “API” and more on how much control the website actually needs.
You should not place a private bearer token in browser code. Use a server-side endpoint or a trusted API provider.
The current X API v2 endpoint is GET /2/users/{id}/tweets. It returns structured post data for the specified user ID.
The timeline endpoint uses a numeric user ID. If your application starts with a username, resolve it to an ID before requesting the timeline.
For a normal company or documentation website, a cache window of several minutes is usually more practical than requesting fresh data for every visitor. The exact interval depends on how time-sensitive the content is.
Only data that the authenticated request is allowed to access can be returned. A website should not assume that a private account can be displayed as a public feed.
Use the official API if the website only needs one focused X workflow and the team is comfortable managing authentication and response handling.
Use KeyAPI’s Twitter API when Twitter is part of a larger data workflow involving several social platforms or when you want to keep your application’s data layer more consistent.