Twitter WebSocket API 快速开始
几分钟内连接 TweetStream 的实时 Twitter 流式替代方案
开始使用
大多数客户端都会使用 WebSocket 子协议认证,把 API Key 放进协议列表即可。如果你的运行环境无法这样传递令牌,也可以使用 Bearer 认证头或 apiKey 查询参数。
本快速开始展示如何通过 WebSocket 实时接收 tweet、account 与 control 事件。如果你在评估 Twitter 流式 API 替代方案,从这里开始。
连接详情
| 端点 | wss://ws.tweetstream.io/ws |
| 协议 1 | tweetstream.v1 |
| 协议 2 | tweetstream.auth.token.YOUR_API_KEY |
快速开始示例
复制以下代码即可立即连接:
const API_KEY = 'YOUR_API_KEY'; // Get your key from the dashboard
const WS_URL = 'wss://ws.tweetstream.io/ws';
const protocols = [
'tweetstream.v1',
`tweetstream.auth.token.${API_KEY}`,
];
const ws = new WebSocket(WS_URL, protocols);
ws.onopen = () => {
console.log('Connected to TweetStream!');
};
ws.onmessage = (event) => {
const envelope = JSON.parse(event.data);
if (envelope.t === 'tweet' && envelope.op === 'content') {
const tweet = envelope.d;
const author = tweet.author?.handle ?? tweet.author?.name ?? 'unknown';
console.log(`[${author}] ${tweet.text}`);
}
};
ws.onclose = () => {
console.log('WebSocket closed');
};
ws.onerror = (error) => {
console.error('WebSocket error', error);
};生产示例
生产环境请加入重连处理:
type VerifiedType = 'blue' | 'business' | 'government' | 'none';
type TweetAuthor = {
id?: string;
handle?: string;
name?: string;
platform?: 'twitter' | 'truth_social';
profileImage?: string;
followersCount?: number;
verifiedType?: VerifiedType;
};
type Media = {
url: string;
type?: 'image' | 'video' | 'gif';
thumbnail?: string;
};
type TweetContent = {
tweetId: string;
text: string;
createdAt: number;
author: TweetAuthor;
link?: string;
media?: Media[];
ref?: {
type: 'reply' | 'quote' | 'retweet';
tweetId?: string;
text?: string;
author?: TweetAuthor;
media?: Media[];
};
};
type MetaSource = 'text' | 'ocr';
type DetectedCexMarket = {
exchange: 'bybit' | 'binance' | 'hyperliquid';
symbol?: string;
priceUsd?: number;
url?: string;
baseAsset?: string;
quoteAsset?: string;
sources: MetaSource[];
};
type DetectedPredictionMarket = {
exchange: 'polymarket' | 'kalshi';
marketId?: string;
title?: string;
priceUsd?: number;
url?: string;
sources: MetaSource[];
};
type DetectedToken = {
symbol?: string;
name?: string;
contract?: string;
chain?: string;
networkId?: number;
priceUsd?: number;
sources: MetaSource[];
};
type TweetMeta = {
tweetId: string;
ocr?: {
text: string;
};
detected?: {
tokens?: Array<{
symbol?: string;
name?: string;
contract?: string;
chain?: string;
networkId?: number;
priceUsd?: number;
sources: Array<'text' | 'ocr'>;
}>;
cex?: Array<{
exchange: 'bybit' | 'binance' | 'hyperliquid';
symbol?: string;
priceUsd?: number;
url?: string;
baseAsset?: string;
quoteAsset?: string;
sources: Array<'text' | 'ocr'>;
}>;
prediction?: Array<{
exchange: 'polymarket' | 'kalshi';
marketId?: string;
title?: string;
priceUsd?: number;
url?: string;
sources: Array<'text' | 'ocr'>;
}>;
};
};
type Media = {
url: string;
type?: 'image' | 'video' | 'gif';
thumbnail?: string;
};
type TweetUpdate = {
tweetId: string;
text?: string;
media?: Media[];
ref?: TweetContent['ref'];
};
type AccountEventActor = TweetAuthor & {
banner?: string;
bio?: string;
location?: string;
url?: string;
websiteUrl?: string;
followingCount?: number;
};
type ProfileUpdateEvent = {
kind: 'PROFILE';
eventId: string;
observedAt: number;
actor: AccountEventActor;
changes: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
previous?: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
};
type FollowEvent = {
kind: 'FOLLOW';
eventId: string;
observedAt: number;
actor: AccountEventActor;
target: AccountEventActor;
};
type Envelope<T extends object> = {
v: 1;
t: 'tweet' | 'account' | 'control';
op:
| 'content'
| 'meta'
| 'update'
| 'delete'
| 'profile_update'
| 'follow'
| 'auth_ping'
| 'auth_pong'
| 'twitter_handles_result';
id?: string;
ts: number;
d: T;
};
type TwitterHandlesResult = {
action: 'follow' | 'unfollow';
requestId: string | null;
results: Array<{
input: string;
normalizedHandle?: string;
twitterId?: string;
state: string;
message?: string;
}>;
error: string | null;
};
const API_KEY = process.env.TWEETSTREAM_API_KEY ?? 'YOUR_API_KEY';
const WS_URL = 'wss://ws.tweetstream.io/ws';
const PROTOCOLS = ['tweetstream.v1', `tweetstream.auth.token.${API_KEY}`];
let ws: WebSocket | null = null;
let reconnectTimer: ReturnType<typeof setTimeout> | undefined;
function connect() {
ws = new WebSocket(WS_URL, PROTOCOLS);
ws.onopen = () => {
console.log('Connected to TweetStream');
};
ws.onmessage = (event) => {
const envelope = JSON.parse(event.data) as Envelope<Record<string, unknown>>;
if (envelope.t === 'tweet') {
if (envelope.op === 'content') {
const tweet = envelope.d as TweetContent;
const author = tweet.author?.handle ?? tweet.author?.name ?? 'unknown';
const platform = tweet.author?.platform ?? 'twitter';
console.log(`[CONTENT] ${author} (${platform}): ${tweet.text}`);
} else if (envelope.op === 'update') {
const update = envelope.d as TweetUpdate;
console.log(`[UPDATE] ${update.tweetId}`, update);
} else if (envelope.op === 'meta') {
const meta = envelope.d as TweetMeta;
console.log(`[META] ${meta.tweetId}`, meta);
}
return;
}
if (envelope.t === 'account') {
if (envelope.op === 'profile_update') {
const profile = envelope.d as ProfileUpdateEvent;
const actor = profile.actor.handle ?? profile.actor.name ?? 'unknown';
console.log(`[PROFILE] ${actor}`, profile.changes);
} else if (envelope.op === 'follow') {
const follow = envelope.d as FollowEvent;
const actor = follow.actor.handle ?? follow.actor.name ?? 'unknown';
const target = follow.target.handle ?? follow.target.name ?? 'unknown';
console.log(`[FOLLOW] ${actor} -> ${target}`);
}
return;
}
if (envelope.t === 'control' && envelope.op === 'twitter_handles_result') {
const payload = envelope.d as TwitterHandlesResult;
console.log('[HANDLES RESULT]', payload);
}
};
ws.onclose = (event) => {
console.warn('WebSocket closed', event.code, event.reason);
scheduleReconnect();
};
ws.onerror = (error) => {
console.error('WebSocket error', error);
ws?.close();
};
}
function scheduleReconnect() {
if (reconnectTimer) return;
reconnectTimer = setTimeout(() => {
reconnectTimer = undefined;
connect();
}, 5_000);
}
connect();封装格式
所有消息都使用一致的封装结构:
v- 协议版本(始终为 1)t- 消息族:tweet、account 或 controlop- 操作,例如 content、meta、update、profile_update、follow、twitter_handles_resultts- 毫秒级 Unix 时间戳d- 载荷数据(随类型与操作变化)
常见问题
- 认证失败: 确认 API Key 来自有效订阅
- 连接数已达上限: 关闭现有连接或升级套餐
- 没有收到推文: 确认已在控制台跟踪账号
立即开启实时 Twitter WebSocket 提醒
内置 WebSocket 交付、OCR 与代币检测的 Twitter API 替代方案。
开始 7 天试用起价 $199/月 · Basic/Elite 含 7 天试用 · OCR + 代币检测
