Browser WebSocket
ネイティブの WebSocket API を使って、ウェブブラウザから直接 finlight.me WebSocket API に接続します。これは、ダッシュボード、トレーディング端末、サーバー側プロキシなしでリアルタイムの記事更新を必要とするあらゆるフロントエンドアプリケーションに最適です。
ブラウザの WebSocket API はカスタムヘッダーをサポートしません。認証は x-api-key ヘッダーではなくクエリパラメータで処理されます。API キーは WebSocket の URL に表示されるため、この方法はそれが許容される環境(例:認証済みのダッシュボード)でのみ使用してください。公開されるクライアント側コードで API キーを決して露出しないでください。
仕組み
- API キーをクエリパラメータとして、
wss://wss.finlight.me(エンリッチ)またはwss://wss.finlight.me/raw(raw)に接続します - フィルター条件と
clientNonceを含む JSON メッセージを送信して購読します - 接続を確認する
admitメッセージを受信し、続いて記事が届くとsendArticleメッセージを受信します - 25 秒ごとに
pingメッセージを送信して接続を維持します ws.close()を呼び出して切断します
接続 URL
- Name
エンリッチ- Type
- wss://wss.finlight.me
- Description
完全なエンリッチメントを伴う記事:感情分析、エンティティ抽出、カテゴリ、全文(サブスクリプション階層に応じて)。
- Name
Raw- Type
- wss://wss.finlight.me/raw
- Description
エンリッチメントなしの低レイテンシな raw 記事。速度を最優先し、記事を可能な限り速く取得したいユースケースに最適です。
クエリパラメータ
- Name
apiKey- Type
- string
- Description
finlight の API キー。ブラウザの WebSocket はカスタムヘッダーを設定できないため、認証に使用されます。
- Name
takeover- Type
- string
- Description
同時接続数の上限に達したときに最も古い接続を自動的に置き換えるには
"true"に設定します。
- Name
clientVersion- Type
- string
- Description
クライアントアプリケーションの任意の識別子。例:
"my-dashboard/1.0"
購読メッセージ
接続が開いたら、記事を購読するために JSON メッセージを送信します。サーバーは admit メッセージで応答し、その後、一致する記事のプッシュを開始します。
- Name
clientNonce- Type
- string
- Description
この購読リクエストの一意の識別子(例:UUID)。サーバーは
admit応答でこれを返します。
- Name
query- Type
- string
- Description
関連する記事を見つけるための検索クエリ。高度なクエリをサポートします。
- Name
sources- Type
- string[]
- Description
ソースドメインでフィルタリングします。例:
["www.reuters.com", "www.cnbc.com"]
- Name
excludeSources- Type
- string[]
- Description
特定のソースドメインを除外します。
- Name
tickers- Type
- string[]
- Description
ティッカーシンボルでフィルタリングします。例:
["AAPL", "NVDA"](エンリッチのみ)
- Name
countries- Type
- string[]
- Description
ISO 3166-1 alpha-2 の国コードでフィルタリングします。例:
["US", "DE"](エンリッチのみ)
サーバーメッセージ
サーバーは、メッセージの種類を示す action フィールドを持つ JSON メッセージを送信します:
- Name
admit- Type
- object
- Description
ハンドシェイク成功後に送信されます。
leaseId、serverNow(タイムスタンプ)、およびclientNonceを含みます。
- Name
sendArticle- Type
- object
- Description
購読に一致する新しい記事。記事データは
dataフィールドにあります。
- Name
pong- Type
- object
- Description
pingハートビートへの応答。
- Name
preempted- Type
- object
- Description
接続が別のセッションに置き換えられました(別のクライアントが
takeover: trueで接続したとき)。
- Name
error- Type
- object
- Description
エラーが発生しました。詳細は
dataまたはerrorフィールドを確認してください。
完全な例
自動再接続とハートビートを備えた、最小限でフレームワークに依存しないブラウザ WebSocket クライアント:
- クエリパラメータで認証します
- 接続時に購読メッセージを送信します
- 25 秒のハートビート間隔を維持します
- 指数バックオフ(500 ミリ秒~10 秒)で再接続します
- すべてのサーバーメッセージタイプを処理します
Browser Client
const API_KEY = 'YOUR_API_KEY'
const WSS_URL = 'wss://wss.finlight.me' // Use '/raw' path for raw articles
let ws = null
let pingInterval = null
let reconnectTimeout = null
let reconnectAttempt = 0
function connect(filters = {}) {
const params = new URLSearchParams({
apiKey: API_KEY,
takeover: 'true',
clientVersion: 'my-app/1.0',
})
const url = `${WSS_URL}?${params}`
ws = new WebSocket(url)
ws.onopen = () => {
console.log('Connected')
reconnectAttempt = 0
// Send subscription with filters
ws.send(JSON.stringify({
clientNonce: crypto.randomUUID(),
query: filters.query || '',
language: filters.language || 'en',
sources: filters.sources || [],
tickers: filters.tickers || [],
countries: filters.countries || [],
}))
// Start heartbeat
pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
action: 'ping',
t: Date.now(),
}))
}
}, 25000)
}
ws.onmessage = (event) => {
const msg = JSON.parse(event.data)
switch (msg.action) {
case 'admit':
console.log('Admitted, lease:', msg.leaseId)
break
case 'sendArticle':
console.log('Article:', msg.data.title)
// Handle the article here
break
case 'pong':
break // Heartbeat OK
case 'preempted':
console.warn('Connection replaced')
break
case 'error':
console.error('Server error:', msg.data || msg.error)
break
}
}
ws.onclose = (event) => {
clearInterval(pingInterval)
// Don't reconnect on policy violations
if (event.code === 1008 || event.code === 4002) {
console.error('Connection blocked')
return
}
// Exponential backoff reconnect
const delay = Math.min(500 * 2 ** reconnectAttempt, 10000)
reconnectAttempt++
console.log(`Reconnecting in ${delay}ms...`)
reconnectTimeout = setTimeout(() => connect(filters), delay)
}
ws.onerror = () => console.error('WebSocket error')
}
function disconnect() {
clearInterval(pingInterval)
clearTimeout(reconnectTimeout)
if (ws) ws.close(1000)
}
// Usage
connect({ query: 'Nvidia', language: 'en', countries: ['US'] })
admit Response
{
"action": "admit",
"leaseId": "a1b2c3d4-e5f6-4789-abcd-ef0123456789",
"serverNow": 1708185600000,
"clientNonce": "your-uuid-here"
}
sendArticle Response
{
"action": "sendArticle",
"data": {
"link": "https://www.reuters.com/technology/nvidia-2026-02-17",
"source": "www.reuters.com",
"title": "Nvidia Reports Record Revenue",
"summary": "Nvidia announced record quarterly revenue...",
"publishDate": "2026-02-17T10:30:00Z",
"language": "en",
"sentiment": "positive",
"confidence": 0.92,
"countries": ["US"],
"categories": ["markets", "technology"],
"companies": [
{
"name": "NVIDIA Corporation",
"ticker": "NVDA",
"country": "US"
}
]
}
}
エンリッチと Raw の比較
| 機能 | エンリッチ (/) | Raw (/raw) |
|---|---|---|
| 感情分析 | あり | なし |
| エンティティ抽出(企業) | あり(階層依存) | なし |
| カテゴリ | あり | なし |
| 全文 | あり(階層依存) | なし |
| レイテンシ | 標準 | 最低 |
フィルター:tickers | あり | なし |
フィルター:countries | あり | なし |
フィルター:query、sources、language | あり | あり |
Raw WebSocket の購読は query、sources、excludeSources、language フィルターのみをサポートします。ティッカーと国のフィルターは raw エンドポイントでは黙って無視されます。