Universal Search News API
지정한 국가별 Google News 판을 각 나라 언어로 검색해 중복을 걸러낸 뉴스 기사 목록 하나로 반환합니다. 같은 사건을 다룬 기사는 스토리로 묶어 함께 제공합니다.
GET /v1/search/newsUniversal Search News API는 언제 쓰나요
한 주제를 소셜 플랫폼 전반에서 볼 거면 search/everywhere가 맞습니다. 여러 나라의 뉴스 보도를 한 번에 훑을 때 사용하세요.
API 레퍼런스 영문 원문
Plans your query into search angles, localizes each angle into the language of every requested country edition (one combined LLM call, fail-open), then fans out up to 12 parallel legs per engine and merges the articles into one deduplicated list. Two independent news indexes are available through engines: google (the default, 50 country editions) and bing (49 of those editions). They overlap very little in practice, so asking for both roughly doubles the distinct articles a query returns and is the way to get a text snippet on most rows: the google engine returns headline, publisher, link, image and an exact publish time but rarely a snippet, while the bing engine returns a description on effectively every row. Every article carries engine provenance and a published_at_precision of exact or approximate, because the two indexes do not report publish times with the same fidelity. Every leg reports truthful localization provenance: query_source says whether its keyword was translated, confirmed original, or a fallback_original after a localization failure. Supports streaming via Accept: text/event-stream (the plan_refined chunk always carries the expanded legs with per-leg provenance before any leg settles) and sync via Accept: application/json. Filters: publisher and from/to exact date windows (google engine only; they pin its legs to the primary source), time_range recency, depth per-leg article depth, sort result ordering, max_legs cost cap. Billing is metered and settles down to the work actually done; empty, skipped and failed legs bill 0.
69개 플랫폼을 병렬로 검색합니다
News API로 무엇을 할 수 있을까요
News 엔드포인트가 통합 스키마와 계산 필드를 담은 Universal Search 데이터를 한 번의 요청으로 보내드려요. 스크래핑 인프라를 직접 만들거나 유지할 필요가 없어요.
요청 예시
# GET /v1/search/news: Metered: holds 14 credits per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
# --max-time 60: the API's own time limit for this endpoint.
# --retry 3: retries timeouts, 429 and 5xx, honoring Retry-After.
# -o response.json keeps only the final attempt's body.
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
IDEMPOTENCY_KEY=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')
curl -sS --max-time 60 --retry 3 -o response.json \
-H "x-api-key: YOUR_API_KEY" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
"https://www.socialcrawl.dev/v1/search/news?query=samsung+galaxy+launch&countries=KR%2CUS%2CJP&engines=google%2Cbing&sort=date&time_range=week&from=2026-07-01&to=2026-07-31&publisher=bbc.com&depth=10&max_legs=4" && cat response.json# GET /v1/search/news: Metered: holds 14 credits per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
import os
import random
import time
import uuid
import requests
API_KEY = os.environ.get("SOCIALCRAWL_API_KEY", "YOUR_API_KEY")
TIMEOUT_S = 60 # the API's own time limit for this endpoint.
MAX_RETRIES = 3
URL = "https://www.socialcrawl.dev/v1/search/news"
def backoff(attempt):
# Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
return 2 ** attempt * (0.5 + random.random() / 2)
def socialcrawl(params):
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
idempotency_key = str(uuid.uuid4())
for attempt in range(MAX_RETRIES + 1):
try:
res = requests.get(
URL,
params=params,
headers={"x-api-key": API_KEY, "Idempotency-Key": idempotency_key},
timeout=TIMEOUT_S,
)
body = res.json()
except (requests.RequestException, ValueError):
# A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
if attempt == MAX_RETRIES:
raise
time.sleep(backoff(attempt))
continue
if body["success"]:
return body
error = body["error"]
# Branch on error["type"], never on the message text.
if error["type"] == "RESOURCE_NOT_FOUND":
return None # refunded: nothing to read
retry_after = res.headers.get("Retry-After")
# SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
permanent = error["type"] == "SERVICE_UNAVAILABLE" and retry_after is None
if not error.get("retryable") or permanent or attempt == MAX_RETRIES:
raise RuntimeError(f"{error['type']}: {error['message']} (request_id {body['request_id']})")
# Retry-After (seconds) wins; otherwise back off.
time.sleep(float(retry_after) if retry_after else backoff(attempt))
params = {
"query": "samsung galaxy launch",
"countries": "KR,US,JP",
"engines": "google,bing",
"sort": "date",
"time_range": "week",
"from": "2026-07-01",
"to": "2026-07-31",
"publisher": "bbc.com",
"depth": "10",
"max_legs": "4",
}
body = socialcrawl(params)
if body is not None:
print(body["data"])// GET /v1/search/news: Metered: holds 14 credits per call up front and refunds what the call does not use. Cache hits are free and failed calls are refunded.
// Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
const API_KEY = process.env.SOCIALCRAWL_API_KEY ?? "YOUR_API_KEY";
const TIMEOUT_MS = 60_000; // the API's own time limit for this endpoint.
const MAX_RETRIES = 3;
type Page = { next_cursor: string | null; has_more: boolean };
type SocialCrawlResponse =
| { success: true; data: any; pagination?: Page; credits_used: number; request_id: string }
| { success: false; error: { type: string; message: string; retryable: boolean }; request_id: string };
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
const backoffMs = (attempt: number) => 2 ** attempt * 1000 * (0.5 + Math.random() / 2);
async function socialcrawl(url: URL) {
// One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
const idempotencyKey = crypto.randomUUID();
for (let attempt = 0; ; attempt++) {
let res: Response;
let body: SocialCrawlResponse;
try {
res = await fetch(url, {
headers: {
"x-api-key": API_KEY,
"Idempotency-Key": idempotencyKey,
},
signal: AbortSignal.timeout(TIMEOUT_MS),
});
body = (await res.json()) as SocialCrawlResponse;
} catch (error) {
// A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
if (attempt >= MAX_RETRIES) throw error;
await sleep(backoffMs(attempt));
continue;
}
if (body.success) return body;
// Branch on error.type, never on the message text.
if (body.error.type === "RESOURCE_NOT_FOUND") return null; // refunded: nothing to read
const retryAfter = res.headers.get("Retry-After");
// SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
const permanent = body.error.type === "SERVICE_UNAVAILABLE" && retryAfter === null;
if (!body.error.retryable || permanent || attempt >= MAX_RETRIES) {
throw new Error(`${body.error.type}: ${body.error.message} (request_id ${body.request_id})`);
}
// Retry-After (seconds) wins; otherwise back off.
await sleep(retryAfter ? Number(retryAfter) * 1000 : backoffMs(attempt));
}
}
const url = new URL("https://www.socialcrawl.dev/v1/search/news");
url.searchParams.set("query", "samsung galaxy launch");
url.searchParams.set("countries", "KR,US,JP");
url.searchParams.set("engines", "google,bing");
url.searchParams.set("sort", "date");
url.searchParams.set("time_range", "week");
url.searchParams.set("from", "2026-07-01");
url.searchParams.set("to", "2026-07-31");
url.searchParams.set("publisher", "bbc.com");
url.searchParams.set("depth", "10");
url.searchParams.set("max_legs", "4");
const body = await socialcrawl(url);
if (body) console.log(body.data);파라미터
| 파라미터 | 필수 | 설명 |
|---|---|---|
| query | 예 | News topic or question (1-500 chars). Boolean AND/OR/NOT and quoted phrases are supported; Google advanced operators (site:, intitle:, before:) are rejected. |
| countries | 아니오 | CSV of ISO 3166-1 alpha-2 country codes to search (1-12 of the 50 supported editions, default US). Each country searches its news edition in its default language; duplicates collapse. |
| engines | 아니오 | CSV of news indexes to search: google (default) and bing. Asking for both runs the same plan on each and merges the results, which roughly doubles distinct articles and adds a snippet to most rows. The bing engine serves 49 of the 50 editions (not CN) and is priced per article; `publisher` and `from`/`to` are google-only. |
| sort | 아니오 | Ordering of the merged articles: relevance (default, each engine's own ranking) or date (newest first, undated articles last). (relevance | date) |
| time_range | 아니오 | Recency window (day | week | month | year, default day). Ignored when from/to is present. (day | week | month | year) |
| from | 아니오 | Lower publish-date bound, YYYY-MM-DD or Unix seconds. Pins every leg to the primary news source. |
| to | 아니오 | Upper publish-date bound, YYYY-MM-DD or Unix seconds. Pins every leg to the primary news source. |
| publisher | 아니오 | Bare publisher domain filter (e.g. bbc.com; no scheme or path). Pins every leg to the primary news source. |
| depth | 아니오 | Articles requested per leg (10-100 in steps of 10, default 10). The google engine is priced per call, so depth is free there; the bing engine is priced per article and caps its own legs at 20. |
| max_legs | 아니오 | Hard cap on billable legs (1-12, default 12). The upfront hold shrinks with it. |
| group | 아니오 | Optional. stories groups the articles that report the same event across editions, outlets and languages into data.stories[] ({ id, head_id, member_ids, size, outlets, outlet_count, countries, languages, first_seen, last_seen, judged }), where every id is an article's canonical_url (or url). items[] and its order are unchanged. data.story_grouping reports how many articles were judged and what it cost. An article that could not be judged is its own story with judged: false; if grouping is unavailable, stories is null and data._warnings says stories_unavailable. JSON responses only (ignored on the event stream). Grouping is on by default now (see judgments); group=stories asks for it explicitly with a longer time budget. Free. (stories) |
| judgments | 아니오 | Optional. on (default) or off. On, JSON responses also carry data.stories and data.story_grouping (see group), grouped under a short time budget; when grouping does not finish in time, stories is null and data._warnings says stories_pending (stories_unavailable when it failed). items[], their order and the price are unchanged. off returns the response without them. (on | off) |
Universal Search News API는 무엇을 돌려주나요
이 엔드포인트의 응답 구조와 필드를 보여 주는 예시예요. 값은 이해를 돕기 위한 것이며 실제 조회 결과는 아니에요.
응답 예시 보기
{
"success": true,
"platform": "search",
"endpoint": "/v1/search/news",
"data": {
"query": "samsung electronics",
"search_status": "succeeded",
"plan": {
"topic": "samsung electronics",
"source": "llm",
"degraded": false,
"subqueries": [
{
"id": "sq0",
"label": "Samsung Electronics 재무 실적",
"search_query": "Samsung Electronics quarterly results revenue profit guidance",
"ranking_query": "Focus on earnings, revenue/profit trends, guidance, and investor updates reported by major outlets.",
"weight": 1
}
],
"notes": [
"llm-plan"
]
},
"legs": [
{
"leg_id": "sq0|KR",
"country": "KR",
"language": "ko",
"angle_id": "sq0",
"angle_label": "Samsung Electronics 재무 실적",
"effective_query": "삼성전자 실적 매출 이익 전망",
"query_source": "translated",
"status": "succeeded",
"article_count": 10,
"quarantined_count": 0,
"credits_used": 1,
"latency_ms": 1452,
"error": null
},
{
"leg_id": "sq0|US",
"country": "US",
"language": "en",
"angle_id": "sq0",
"angle_label": "Samsung Electronics 재무 실적",
"effective_query": "Samsung Electronics earnings revenue profit guidance",
"query_source": "translated",
"status": "succeeded",
"article_count": 10,
"quarantined_count": 0,
"credits_used": 1,
"latency_ms": 3177,
"error": null
}
],
"items": [
{
"id": "gn_9599da30",
"title": "키움증권 \"삼성전자 3분기 영업이익 120조 전망, 메모리 가격 20% 오를 것\"",
"url": "https://www.businesspost.co.kr/BP?command=article_view&num=443626",
"canonical_url": "https://www.businesspost.co.kr/BP?command=article_view&num=443626",
"source_name": "비즈니스포스트",
"domain": "www.businesspost.co.kr",
"snippet": null,
"image_url": "https://www.businesspost.co.kr/news/photo/202306/20230629221229_98416.jpg",
"published_at": "2026-07-31T00:57:26.000Z",
"rank": 1,
"placement": "news_search",
"country_code": "KR",
"language_code": "ko",
"angle_id": "sq0",
"effective_query": "삼성전자 실적 매출 이익 전망",
"query_source": "translated",
"legs_returned": [
"sq0|KR"
]
},
{
"id": "gn_2c3f9190",
"title": "Samsung Sees Chip Crunch Through 2028 as Profit Soars to Record",
"url": "https://www.wsj.com/tech/samsungs-chip-earnings-push-net-profit-to-record-cf8711bc",
"canonical_url": "https://www.wsj.com/tech/samsungs-chip-earnings-push-net-profit-to-record-cf8711bc",
"source_name": "WSJ",
"domain": "www.wsj.com",
"snippet": null,
"image_url": "https://images.wsj.net/im-46577202?width=700&height=466",
"published_at": "2026-07-30T08:59:00.000Z",
"rank": 1,
"placement": "news_search",
"country_code": "US",
"language_code": "en",
"angle_id": "sq0",
"effective_query": "Samsung Electronics earnings revenue profit guidance",
"query_source": "translated",
"legs_returned": [
"sq0|US"
]
}
],
"total_articles": 20,
"countries_searched": [
"KR",
"US"
],
"credits_charged": 4,
"methodology_version": "search-news/1.0"
},
"credits_used": 4,
"credits_remaining": 9999,
"request_id": "req_example000000",
"cached": false
}문서에 나온 응답 구조를 보여 주는 예시예요. 값은 이해를 돕기 위한 것이며 운영 환경에서 가져온 응답이 아니에요.
Universal Search News API는 어떻게 동작하나요
API 키와 함께 GET 요청을 보내면, 통합 스키마와 계산 필드를 담은 깔끔한 JSON이 돌아와요.
메서드
GET
응답 형식
JSON
소셜 미디어 데이터를 몇 초 만에 수집하는 방법
개발자를 위한 가장 빠른 소셜 미디어 스크래핑 API. 월간 활성 사용자 100억 명 이상을 포괄하는 69개 플랫폼에서 프로필, 게시물, 댓글, 분석 데이터를 수집하세요.
모든 플랫폼을 하나의 스키마로
동일한 응답 구조로 69개 플랫폼을 조회하세요. 연동은 한 번이면 충분합니다.
단순 수집을 넘어 계산된 필드 제공
엔드포인트가 해당 지표를 지원하고 계산에 필요한 원본 값이 있을 때, 정규화된 레코드에 engagement_rate, estimated_reach, content_category, language를 함께 담아 바로 활용할 수 있습니다.
코드 한 줄 쓰기 전에, 데이터부터
Visual Data Explorer에 URL만 붙여넣으면 결과 카드와 정형화된 테이블, CSV 내보내기를 바로 사용할 수 있습니다.
import requests
response = requests.get(
'https://www.socialcrawl.dev/v1/tiktok/profile',
params={'handle': 'charlidamelio'},
headers={'x-api-key': 'sc_YOUR_API_KEY'}
)
data = response.json(){
"success": true,
"platform": "tiktok",
"data": {
"author": {
"username": "charlidamelio",
"followers": 152400000
},
"engagement": {
"likes": 12400000000,
"engagement_rate": 0.087
},
"metadata": {
"language": "en",
"content_category": "lifestyle"
}
}
}자주 묻는 질문
API, 요금제, 기능에 대한 질문과 답변입니다.
문의하기SocialCrawl 뉴스 검색 API가 뭔가요?
어떤 나라 뉴스를 검색할 수 있나요?
요금은 얼마인가요?
검색어 현지화는 어떻게 동작하나요?
결과를 스트리밍으로 받을 수 있나요?
AI에게 SocialCrawl을 물어보세요
Universal Search News 데이터, 가져올 준비 되셨어요?
API 키 받고 60초 안에 Universal Search 데이터를 받아 가세요.
