curl --request POST \
--url https://api.cloro.dev/v1/monitor/google/news \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"query": "climate change",
"country": "US",
"gl": "us",
"hl": "en",
"device": "desktop",
"pages": 1,
"include": {
"html": false
}
}
'import requests
url = "https://api.cloro.dev/v1/monitor/google/news"
payload = {
"query": "climate change",
"country": "US",
"gl": "us",
"hl": "en",
"device": "desktop",
"pages": 1,
"include": { "html": False }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
query: 'climate change',
country: 'US',
gl: 'us',
hl: 'en',
device: 'desktop',
pages: 1,
include: {html: false}
})
};
fetch('https://api.cloro.dev/v1/monitor/google/news', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloro.dev/v1/monitor/google/news",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => 'climate change',
'country' => 'US',
'gl' => 'us',
'hl' => 'en',
'device' => 'desktop',
'pages' => 1,
'include' => [
'html' => false
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloro.dev/v1/monitor/google/news"
payload := strings.NewReader("{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloro.dev/v1/monitor/google/news")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/monitor/google/news")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"newsResults": [
{
"position": 1,
"title": "Major Climate Summit Reaches Historic Agreement",
"link": "https://example.com/climate-summit-agreement",
"snippet": "World leaders agreed on new climate targets at the summit...",
"source": "The Guardian",
"date": "2 hours ago",
"page": 1,
"thumbnail": "https://example.com/images/climate-summit.jpg",
"redirectLink": "https://www.google.com/goto?url=CAESaAHrOzAVev0pi_wnTxm1qpiZTmMyAllabLr1or10ZCfvJKPk"
}
],
"html": [
"https://cdn.cloro.dev/results/a12b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6/page-1.html"
]
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
],
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "CONCURRENCY_LIMIT_EXCEEDED",
"message": "Concurrency limit exceeded",
"details": {
"limit": 10
},
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "REQUEST_CANCELED",
"message": "Request was canceled by client",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "Maximum retries exceeded",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}Extract Google News
Extract structured news articles from Google News including titles, links, snippets, sources, dates, and thumbnails
curl --request POST \
--url https://api.cloro.dev/v1/monitor/google/news \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"query": "climate change",
"country": "US",
"gl": "us",
"hl": "en",
"device": "desktop",
"pages": 1,
"include": {
"html": false
}
}
'import requests
url = "https://api.cloro.dev/v1/monitor/google/news"
payload = {
"query": "climate change",
"country": "US",
"gl": "us",
"hl": "en",
"device": "desktop",
"pages": 1,
"include": { "html": False }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
query: 'climate change',
country: 'US',
gl: 'us',
hl: 'en',
device: 'desktop',
pages: 1,
include: {html: false}
})
};
fetch('https://api.cloro.dev/v1/monitor/google/news', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloro.dev/v1/monitor/google/news",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => 'climate change',
'country' => 'US',
'gl' => 'us',
'hl' => 'en',
'device' => 'desktop',
'pages' => 1,
'include' => [
'html' => false
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloro.dev/v1/monitor/google/news"
payload := strings.NewReader("{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloro.dev/v1/monitor/google/news")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/monitor/google/news")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"climate change\",\n \"country\": \"US\",\n \"gl\": \"us\",\n \"hl\": \"en\",\n \"device\": \"desktop\",\n \"pages\": 1,\n \"include\": {\n \"html\": false\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"newsResults": [
{
"position": 1,
"title": "Major Climate Summit Reaches Historic Agreement",
"link": "https://example.com/climate-summit-agreement",
"snippet": "World leaders agreed on new climate targets at the summit...",
"source": "The Guardian",
"date": "2 hours ago",
"page": 1,
"thumbnail": "https://example.com/images/climate-summit.jpg",
"redirectLink": "https://www.google.com/goto?url=CAESaAHrOzAVev0pi_wnTxm1qpiZTmMyAllabLr1or10ZCfvJKPk"
}
],
"html": [
"https://cdn.cloro.dev/results/a12b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6/page-1.html"
]
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
],
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "CONCURRENCY_LIMIT_EXCEEDED",
"message": "Concurrency limit exceeded",
"details": {
"limit": 10
},
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "REQUEST_CANCELED",
"message": "Request was canceled by client",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "Maximum retries exceeded",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}Request parameters
query and one of country or gl are required; there is no default country. Every other field is optional and listed in the request body schema below.
Response schema
Includes common response fields, plusresult.newsResults: the news articles from every scraped page.
Usage examples
Basic news search
{
"query": "climate change",
"country": "US"
}
Multi-page news search
{
"query": "artificial intelligence",
"pages": 3,
"country": "GB"
}
Mobile news results
The mobile news SERP as seen from an iPhone. Use"device": "android" for Chrome on Android instead:
{
"query": "technology news",
"device": "ios",
"country": "US"
}
Include HTML response
Raw HTML alongside the structured data:{
"query": "sports news",
"country": "US",
"include": {
"html": true
}
}
Authorizations
cloro API key as a bearer token. One key grants every endpoint in this spec; per-key scopes are not available, so a client cannot request a narrower permission. Keys are created and revoked in the dashboard.
Body
Request parameters for monitoring Google News results
- Option 1
- Option 2
ISO 3166-1 alpha-2 country code for localized news results. See List of countries for the codes each provider supports.
AD, AE, AF, AG, AI, AL, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, XK, YE, YT, ZA, ZM, ZW "US"
Alternative to country, using Google's own parameter name for the result geography. Same ISO 3166-1 alpha-2 codes, accepted in either case (us or US), and must be a country the endpoint supports — see GET /v1/countries. Provide country or gl; sending both with different values is a 400.
"us"
Number of news results pages to scrape (1-10). Paid add-on: +2 credits per page after the first (pricing).
1 <= x <= 101
Was this page helpful?