Skip to content

Build a News Dashboard with Article Counts ​

Use article counts grouped by category, country, publisher bias or another field. Group dates or numeric scores into intervals to build timeline and distribution charts.

Step 1: Count articles by field ​

Set facet=true and list up to 5 fields in facet.field. Counts are computed over everything that matches your filters, not just the current page.

bash
curl "https://api.apitube.io/v1/news/everything?facet=true&facet.field=category.id,source.country.id,source.bias&facet.limit=10&per_page=1&api_key=YOUR_API_KEY"
python
import requests

response = requests.get(
    "https://api.apitube.io/v1/news/everything",
    params={
        "facet": "true",
        "facet.field": "category.id,source.country.id,source.bias",
        "facet.limit": "10",
        "per_page": "1",
        "api_key": "YOUR_API_KEY",
    },
)
print(response.json())
javascript
const params = new URLSearchParams({ "facet": "true", "facet.field": "category.id,source.country.id,source.bias", "facet.limit": "10", "per_page": "1", "api_key": "YOUR_API_KEY" });
const response = await fetch(`https://api.apitube.io/v1/news/everything?${params}`);
const data = await response.json();
console.log(data);
php
$query = http_build_query(["facet" => "true", "facet.field" => "category.id,source.country.id,source.bias", "facet.limit" => "10", "per_page" => "1", "api_key" => "YOUR_API_KEY"]);
$response = file_get_contents("https://api.apitube.io/v1/news/everything?$query");
$data = json_decode($response, true);
print_r($data);
go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	u, _ := url.Parse("https://api.apitube.io/v1/news/everything")
	q := u.Query()
	q.Set("facet", "true")
	q.Set("facet.field", "category.id,source.country.id,source.bias")
	q.Set("facet.limit", "10")
	q.Set("per_page", "1")
	q.Set("api_key", "YOUR_API_KEY")
	u.RawQuery = q.Encode()

	resp, _ := http.Get(u.String())
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var data map[string]any
	json.Unmarshal(body, &data)
	fmt.Println(data)
}
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.apitube.io/v1/news/everything?facet=true&facet.field=category.id,source.country.id,source.bias&facet.limit=10&per_page=1&api_key=YOUR_API_KEY"))
            .GET()
            .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
text
Write a script in your preferred language that calls the APITube News API:

GET https://api.apitube.io/v1/news/everything?facet=true&facet.field=category.id,source.country.id,source.bias&facet.limit=10&per_page=1

Read the API key from an environment variable (do not hardcode it), handle request
errors, and print the key fields of each result.
Docs: https://docs.apitube.io/platform/news-api/everything

The response carries a facets object keyed by field name, each holding { value, count } pairs:

json
{
    "facets": {
        "source.bias": [
            { "value": 0, "count": 3809437 },
            { "value": 2, "count": 3746702 },
            { "value": 1, "count": 1868553 }
        ]
    }
}
  • Pie or bar widget — facets["category.id"], feed the value into the category list to get a readable label.
  • Map widget — facets["source.country.id"].
  • Bias split — facets["source.bias"], where 0 is left, 1 is center and 2 is right. Sources with no bias rating are returned under their own value — drop it before charting.
  • Hide rare values — raise facet.mincount to exclude values that appear in only a few articles.

Step 2: Draw the publication timeline ​

Range facets group a date or number into intervals. For a publication timeline, set facet.range.field=published_at and choose a gap: 1HOUR, 1DAY or 1MONTH.

bash
curl "https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=published_at&facet.range.start=2026-07-20&facet.range.end=2026-07-27&facet.range.gap=1DAY&per_page=1&api_key=YOUR_API_KEY"
python
import requests

response = requests.get(
    "https://api.apitube.io/v1/news/everything",
    params={
        "facet.range": "true",
        "facet.range.field": "published_at",
        "facet.range.start": "2026-07-20",
        "facet.range.end": "2026-07-27",
        "facet.range.gap": "1DAY",
        "per_page": "1",
        "api_key": "YOUR_API_KEY",
    },
)
print(response.json())
javascript
const params = new URLSearchParams({ "facet.range": "true", "facet.range.field": "published_at", "facet.range.start": "2026-07-20", "facet.range.end": "2026-07-27", "facet.range.gap": "1DAY", "per_page": "1", "api_key": "YOUR_API_KEY" });
const response = await fetch(`https://api.apitube.io/v1/news/everything?${params}`);
const data = await response.json();
console.log(data);
php
$query = http_build_query(["facet.range" => "true", "facet.range.field" => "published_at", "facet.range.start" => "2026-07-20", "facet.range.end" => "2026-07-27", "facet.range.gap" => "1DAY", "per_page" => "1", "api_key" => "YOUR_API_KEY"]);
$response = file_get_contents("https://api.apitube.io/v1/news/everything?$query");
$data = json_decode($response, true);
print_r($data);
go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	u, _ := url.Parse("https://api.apitube.io/v1/news/everything")
	q := u.Query()
	q.Set("facet.range", "true")
	q.Set("facet.range.field", "published_at")
	q.Set("facet.range.start", "2026-07-20")
	q.Set("facet.range.end", "2026-07-27")
	q.Set("facet.range.gap", "1DAY")
	q.Set("per_page", "1")
	q.Set("api_key", "YOUR_API_KEY")
	u.RawQuery = q.Encode()

	resp, _ := http.Get(u.String())
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var data map[string]any
	json.Unmarshal(body, &data)
	fmt.Println(data)
}
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=published_at&facet.range.start=2026-07-20&facet.range.end=2026-07-27&facet.range.gap=1DAY&per_page=1&api_key=YOUR_API_KEY"))
            .GET()
            .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
text
Write a script in your preferred language that calls the APITube News API:

GET https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=published_at&facet.range.start=2026-07-20&facet.range.end=2026-07-27&facet.range.gap=1DAY&per_page=1

Read the API key from an environment variable (do not hardcode it), handle request
errors, and print the key fields of each result.
Docs: https://docs.apitube.io/platform/news-api/everything

Each interval appears under <field>_ranges with its start, end and article count. Plot these values directly:

json
{
    "facets": {
        "published_at_ranges": [
            { "range_start": "2026-07-24", "range_end": "2026-07-25", "count": 283467 },
            { "range_start": "2026-07-25", "range_end": "2026-07-26", "count": 174354 },
            { "range_start": "2026-07-26", "range_end": "2026-07-27", "count": 165699 }
        ]
    }
}

Step 3: Chart sentiment scores ​

The same approach works with numeric fields. sentiment.overall.score ranges from -1 to 1. An interval size of 0.25 divides the scores into eight groups, from very negative to very positive.

bash
curl "https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=sentiment.overall.score&facet.range.start=-1&facet.range.end=1&facet.range.gap=0.25&per_page=1&api_key=YOUR_API_KEY"
python
import requests

response = requests.get(
    "https://api.apitube.io/v1/news/everything",
    params={
        "facet.range": "true",
        "facet.range.field": "sentiment.overall.score",
        "facet.range.start": "-1",
        "facet.range.end": "1",
        "facet.range.gap": "0.25",
        "per_page": "1",
        "api_key": "YOUR_API_KEY",
    },
)
print(response.json())
javascript
const params = new URLSearchParams({ "facet.range": "true", "facet.range.field": "sentiment.overall.score", "facet.range.start": "-1", "facet.range.end": "1", "facet.range.gap": "0.25", "per_page": "1", "api_key": "YOUR_API_KEY" });
const response = await fetch(`https://api.apitube.io/v1/news/everything?${params}`);
const data = await response.json();
console.log(data);
php
$query = http_build_query(["facet.range" => "true", "facet.range.field" => "sentiment.overall.score", "facet.range.start" => "-1", "facet.range.end" => "1", "facet.range.gap" => "0.25", "per_page" => "1", "api_key" => "YOUR_API_KEY"]);
$response = file_get_contents("https://api.apitube.io/v1/news/everything?$query");
$data = json_decode($response, true);
print_r($data);
go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	u, _ := url.Parse("https://api.apitube.io/v1/news/everything")
	q := u.Query()
	q.Set("facet.range", "true")
	q.Set("facet.range.field", "sentiment.overall.score")
	q.Set("facet.range.start", "-1")
	q.Set("facet.range.end", "1")
	q.Set("facet.range.gap", "0.25")
	q.Set("per_page", "1")
	q.Set("api_key", "YOUR_API_KEY")
	u.RawQuery = q.Encode()

	resp, _ := http.Get(u.String())
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var data map[string]any
	json.Unmarshal(body, &data)
	fmt.Println(data)
}
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=sentiment.overall.score&facet.range.start=-1&facet.range.end=1&facet.range.gap=0.25&per_page=1&api_key=YOUR_API_KEY"))
            .GET()
            .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
text
Write a script in your preferred language that calls the APITube News API:

GET https://api.apitube.io/v1/news/everything?facet.range=true&facet.range.field=sentiment.overall.score&facet.range.start=-1&facet.range.end=1&facet.range.gap=0.25&per_page=1

Read the API key from an environment variable (do not hardcode it), handle request
errors, and print the key fields of each result.
Docs: https://docs.apitube.io/platform/news-api/everything

You can also group read_time by intervals of 5, source.rank.opr by intervals of 2, or media.images.count by the number of images.

Filters apply before articles are counted. Add industry.id to limit the dashboard's counts to one industry:

python
import requests

def dashboard(api_key, **filters):
    params = {
        "facet": "true",
        "facet.field": "category.id,source.country.id",
        "facet.range": "true",
        "facet.range.field": "published_at",
        "facet.range.start": "2026-07-20",
        "facet.range.end": "2026-07-27",
        "facet.range.gap": "1DAY",
        "per_page": 1,
        "api_key": api_key,
        **filters,
    }
    return requests.get("https://api.apitube.io/v1/news/everything", params=params).json()["facets"]

Tip: set per_page=1 when you only need facet counts. Counts cover all matching articles, regardless of page size.