Company News API: Build a Multilingual Monitor in Python
Learn how to build a multilingual company news monitor in Python. Resolve a company to a stable entity, search five languages and export source-linked coverage to CSV.
Tracking a company sounds like a keyword-search problem. Enter the company name, collect the latest articles and repeat the query tomorrow.
That approach breaks quickly when the name is ambiguous, translated or shared with an ordinary word. Searching only one spelling can also miss coverage that uses an alias or a different-language form of the company name.
Meta Platforms is a useful example. Meta is the company name, but it also means a goal or target in Spanish and Portuguese. A literal search can retrieve sports results, production targets and public-policy goals. Meanwhile, a relevant article may mention Facebook, Instagram or WhatsApp without putting Meta in the headline.
This tutorial builds a company news monitor that handles that problem with a stable company entity rather than a loose keyword. The Python script will:
- Resolve Meta Platforms to its NewsAPI.ai concept URI.
- Search English, Spanish, Portuguese, German and French coverage.
- Keep the latest source-linked articles from each language.
- Skip records marked as duplicates.
- Preserve event IDs so related coverage can be grouped later.
- Export the normalized results to CSV.
The same workflow can be adapted for a competitor watchlist, portfolio monitor, reputation dashboard or market-intelligence pipeline.
Why company monitoring needs more than keywords
A keyword tells a search system which text appeared. It does not necessarily identify what that text represents.
Consider a query for Meta:
- In Spanish,
metacan mean a goal, target or finish line. - In Portuguese,
metaandmetasare commonly used for targets and objectives. - In English, the term appears in phrases such as meta-analysis and metadata.
- Relevant company coverage may lead with Facebook, Instagram, WhatsApp, Threads or a product name instead.
Maintaining a separate keyword dictionary for every language is possible, but it becomes fragile. The list has to include translations, aliases and exclusions for common-word collisions. Products and subsidiaries may require their own concepts or keywords when they are part of the monitoring scope.
NewsAPI.ai provides a different search unit: the concept URI. A concept is a disambiguated entity such as a company, person, location or topic. Meta Platforms is represented by:
http://en.wikipedia.org/wiki/Meta_Platforms
That identifier remains the same across language-specific searches. The NewsAPI.ai media-monitoring documentation explains that concept search can recognize aliases and find cross-language coverage without relying only on one literal spelling.

What the live test found
Before building the monitor, we compared literal keyword search with entity search.
The test used articles published from 5 through 11 October 2026. We ran a keyword query for Meta and a concept query for Meta Platforms in five languages. Both searches used news content, newest-first sorting and isDuplicateFilter=skipDuplicates. We retained the latest 50 results from every query.
| Language | Keyword matches | Entity matches | Keyword sample also tagged as Meta Platforms | Entity titles containing the word Meta |
|---|---|---|---|---|
| English | 6,960 | 4,873 | 27 of 50 | 4 of 50 |
| Spanish | 7,277 | 666 | 1 of 50 | 0 of 50 |
| Portuguese | 3,882 | 637 | 14 of 50 | 2 of 50 |
| German | 613 | 459 | 33 of 50 | 11 of 50 |
| French | 660 | 326 | 23 of 50 | 6 of 50 |
The totals do not measure index size or universal accuracy. Keyword and concept searches use different retrieval semantics. The useful signal is the structure of the returned samples.
Only one of the latest 50 Spanish keyword results was also tagged with the exact Meta Platforms concept. The Portuguese overlap was 14 of 50. The untagged sample included headlines about a marathon finish line, MotoGP, government targets and Petrobras production goals. Because the keyword query searched article bodies by default, these headlines illustrate likely common-word collisions, not a manual precision score.
At the same time, most entity-search headlines did not contain the literal word Meta. In the Spanish entity sample, none of the 50 headlines used it. The results instead included coverage involving WhatsApp, Facebook, social networks, AI spending and platform regulation.
This is the main advantage of entity-based company monitoring. It avoids depending on one ambiguous word while still connecting coverage to the intended organization.
The concept tag is not a manual relevance score. An article can mention Meta Platforms as a secondary subject, and an untagged keyword result may still discuss the company in a way the enrichment system did not capture. We therefore report the overlap as a reproducible diagnostic, not as a claim that entity search is a specific percentage more accurate.

Prerequisites
You need:
- Python 3
- The
requestspackage - A NewsAPI.ai API key
Create an account through the NewsAPI.ai registration page. NewsAPI.ai currently describes free access as 2,000 searches with no credit card required. Its token documentation describes this as 2,000 testing tokens, subject to a limit of 500 tokens per day, and states that a recent article search normally costs one token. Check the plans page and token documentation for current allowances and usage conditions.
Install the dependency:
python -m pip install requests
This tutorial calls the REST API directly with requests. NewsAPI.ai also provides an official Python SDK guide for projects that prefer its eventregistry package.
Store the API key in an environment variable rather than putting it in the script:
export NEWSAPI_AI_KEY="YOUR_API_KEY"
On Windows PowerShell:
$env:NEWSAPI_AI_KEY="YOUR_API_KEY"
Complete Python company-news monitor
Save the following code as company_news_monitor.py:
#!/usr/bin/env python3
"""Minimal example for the multilingual company-monitoring tutorial."""
import csv
import os
from datetime import datetime, timedelta, timezone
import requests
API_ROOT = "https://eventregistry.org/api/v1"
API_KEY = os.environ.get("NEWSAPI_AI_KEY")
COMPANY = "Meta Platforms"
LANGUAGES = ["eng", "spa", "por", "deu", "fra"]
RESULTS_PER_LANGUAGE = int(os.environ.get("RESULTS_PER_LANGUAGE", "20"))
OUTPUT_FILE = "meta_company_news.csv"
CSV_FIELDS = [
"company",
"concept_uri",
"article_uri",
"language",
"published_at",
"title",
"source",
"source_domain",
"source_country",
"url",
"event_uri",
]
def post(path, payload):
payload["apiKey"] = API_KEY
response = requests.post(
f"{API_ROOT}/{path}",
json=payload,
timeout=60,
)
response.raise_for_status()
data = response.json()
if isinstance(data, dict) and data.get("error"):
raise RuntimeError(f"NewsAPI.ai error: {data['error']}")
return data
def resolve_company(name):
candidates = post(
"suggestConceptsFast",
{
"prefix": name,
"source": ["concepts"],
"lang": "eng",
"conceptLang": ["eng"],
"count": 20,
},
)
if not isinstance(candidates, list):
raise RuntimeError("Unexpected response from suggestConceptsFast")
for candidate in candidates:
label = (candidate.get("label") or {}).get("eng", "")
if candidate.get("type") == "org" and label.casefold() == name.casefold():
return candidate["uri"]
raise RuntimeError(f"No exact organization match found for {name!r}")
def get_source_country(article):
source = article.get("source") or {}
location = source.get("location") or {}
country = (
location
if location.get("type") == "country"
else location.get("country") or {}
)
return (country.get("label") or {}).get("eng", "")
def search_language(concept_uri, language, date_start, date_end):
data = post(
"article/getArticles",
{
"action": "getArticles",
"resultType": "articles",
"conceptUri": concept_uri,
"lang": language,
"dateStart": date_start,
"dateEnd": date_end,
"dataType": ["news"],
"isDuplicateFilter": "skipDuplicates",
"articlesPage": 1,
"articlesCount": RESULTS_PER_LANGUAGE,
"articlesSortBy": "date",
"articlesSortByAsc": False,
"articlesArticleBodyLen": 0,
"includeSourceLocation": True,
},
)
articles = data.get("articles") if isinstance(data, dict) else None
if not isinstance(articles, dict):
raise RuntimeError("Unexpected response from article/getArticles")
return articles
end_date = datetime.now(timezone.utc).date() - timedelta(days=1)
start_date = end_date - timedelta(days=6)
if not API_KEY:
raise SystemExit("Set NEWSAPI_AI_KEY before running this script")
if not 1 <= RESULTS_PER_LANGUAGE <= 100:
raise ValueError("RESULTS_PER_LANGUAGE must be between 1 and 100")
company_uri = resolve_company(COMPANY)
rows = []
print(f"Tracking {COMPANY}: {company_uri}")
print(f"Publication window: {start_date} through {end_date}")
for language in LANGUAGES:
result = search_language(
company_uri,
language,
start_date.isoformat(),
end_date.isoformat(),
)
articles = result.get("results") or []
print(f"{language}: {result.get('totalResults', 0):,} matches")
for article in articles:
source = article.get("source") or {}
rows.append(
{
"company": COMPANY,
"concept_uri": company_uri,
"article_uri": article.get("uri") or "",
"language": language,
"published_at": article.get("dateTime") or "",
"title": article.get("title") or "",
"source": source.get("title") or "",
"source_domain": source.get("uri") or "",
"source_country": get_source_country(article),
"url": article.get("url") or "",
"event_uri": article.get("eventUri") or "",
}
)
rows.sort(key=lambda row: row["published_at"], reverse=True)
with open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as handle:
writer = csv.DictWriter(handle, fieldnames=CSV_FIELDS)
writer.writeheader()
writer.writerows(rows)
print(f"Saved {len(rows)} source-linked articles to {OUTPUT_FILE}")
Run it with:
python company_news_monitor.py
The code was verified against the live API on 2 November 2026. A small verification run resolved the correct Meta Platforms concept and returned current results in all five configured languages. The first run makes one concept-suggestion request and five separate article-search requests.

How the monitor works
1. Resolve the company once
The script first calls suggestConceptsFast. This maps a company label to the stable concept URI used in later article searches.
The API may return several candidates for an ambiguous prefix. Searching Meta, for example, can produce concepts such as metal, metabolism and Meta Platforms. The code therefore requires both:
- an organization result, identified by
type == "org"; - an exact English label match for
Meta Platforms.
This prevents the script from silently selecting the first popular concept with a similar prefix. The Suggest concepts documentation describes the endpoint and its returned candidates.
For a production watchlist, resolve and store each company URI during configuration. Reuse the URI for scheduled searches instead of repeating autosuggest on every run.
2. Search each language separately
The script sends one article/getArticles request for each ISO 639-2 language code:
| Code | Language |
|---|---|
eng |
English |
spa |
Spanish |
por |
Portuguese |
deu |
German |
fra |
French |
Separate requests are useful even when an API can accept several languages. They produce a clear total for every language and make it easier to route results to regional teams.
The date window uses the seven calendar dates before the current UTC date. Excluding the current date avoids mixing a partial day with previous full dates. Late indexing can still add records to an earlier publication date, so this should not be treated as a permanently frozen dataset. The official Python guide defines dateStart as on or after the supplied date and dateEnd as before or on the supplied date.
3. Scan with metadata, not full bodies
articlesArticleBodyLen is set to 0 because this first pass needs titles, links and metadata rather than complete article text.
This keeps the response small. A later workflow can retrieve full content only for the selected articles that need summarization, classification or deeper review. The NewsAPI.ai article examples show how returned fields and body length can be adjusted.
4. Keep source links and event IDs
Every CSV row contains the original article URL and source domain. This makes the output suitable for an analyst queue or briefing in which every item should be traceable to its publisher.
The script also preserves event_uri. NewsAPI.ai defines an event as a group of articles covering the same detected development. A later step can group those records and present one story with several sources instead of treating every article as a separate event. This follows the event model described on the media-monitoring page.
5. Filter duplicates, but expect repeated coverage
isDuplicateFilter is set to skipDuplicates. This removes records the API has identified as copies.
That does not guarantee that every returned headline is unique. Several publishers can cover the same event or publish similar wire headlines without every record receiving the same duplicate label. If the application needs one item per real-world development, group by event_uri in addition to using duplicate filtering.
What the CSV contains
The resulting file contains:
company: the monitored organization;concept_uri: the resolved NewsAPI.ai company concept;article_uri: the NewsAPI.ai identifier for the article;language: the article language;published_at: the publication timestamp;title: the original-language headline;source: the readable publisher name;source_domain: the publisher domain;source_country: the available publisher-country metadata;url: the source article;event_uri: the related NewsAPI.ai event, when available.
Language and source country should not be treated as the same field. A Spanish-language article can be published in Spain, Argentina, Mexico, the United States or another market. Publisher-country metadata can also be missing, so applications should retain an empty or unknown value rather than guessing from the language. NewsAPI.ai's filter guide makes the same distinction between event location and source location.

How to adapt the monitor
Track another company
Change:
COMPANY = "Meta Platforms"
to the exact organization label you want to resolve. If no exact match is found, inspect the candidates returned by suggestConceptsFast and select the intended organization URI explicitly.
For companies with common names, do not fall back automatically to keyword search. Confirm the entity first.
Add or remove languages
Edit the language list:
LANGUAGES = ["eng", "spa", "por", "deu", "fra"]
Choose languages based on the markets that matter to the company. A larger list is not automatically better. Each language request is a separate article-search action, and regional value depends on publisher coverage and query relevance.
Focus on a risk or business signal
Entity search answers who the article is about. Keywords and categories can narrow what happened.
For example, a risk monitor could combine the company concept with terms for investigations, recalls, sanctions or data breaches. An investor workflow could add earnings, guidance, acquisition or regulatory keywords.
The important pattern is to keep the company entity as the stable anchor and use keywords for the event language around it.
Prefer relevance instead of recency
This monitor sorts by date because its purpose is to identify what appeared most recently. For a research task, change:
"articlesSortBy": "date"
to:
"articlesSortBy": "rel"
Newest-first monitoring can include articles where the company is a secondary subject. Relevance sorting can surface more central coverage, but it is less suitable for a strict chronological alert feed.
Avoid sending the same article twice
A scheduled daily monitor should save the article_uri after delivery. The example CSV includes this field. On the next run, compare the new response with the stored set and emit only unseen records. Keep an overlapping date window so an article added to the index after its publication date can still be collected.
For higher-frequency ingestion, NewsAPI.ai provides a separate minute-stream endpoint. Its documented continuation pattern uses the returned newestUri values, rather than the latest publication timestamp, to request articles imported after the previous call. That cursor belongs to the minute-stream workflow and is not returned by the article/getArticles request used in this tutorial.
Where to take the project next
The CSV is a useful first product, but the structured response supports more advanced workflows:
- Group articles by
event_urito create one row per development. - Rank events by the number and diversity of reporting sources.
- Retrieve full text only for selected articles.
- Generate a source-linked daily company briefing.
- Compare how the same company event is covered across languages or publisher countries.
- Add several company entities to build a competitor watchlist.
- Send new high-priority events to email, Slack or a dashboard.
The most valuable improvement is usually event grouping. A monitoring team rarely needs 25 versions of the same announcement. It needs to know that one event occurred, how widely it was covered and which sources added distinct information.
Final takeaway
A company name is not always a safe search query. Common-word collisions, language differences and alternative names can make literal monitoring noisy and incomplete. Products and subsidiaries should be added explicitly when the monitoring brief requires them.
A company news API becomes more useful when the company is represented as a stable entity. The Python workflow in this tutorial resolves that entity once, searches five languages, keeps traceable source links and exports a practical monitoring dataset.
The October live test showed why the distinction matters. Literal Meta searches returned thousands of matches, but the overlap with the resolved Meta Platforms concept varied sharply by language. Concept search removed dependence on that single word. The returned sample also contained company-tagged articles whose headlines led with names such as Facebook or WhatsApp. That observation does not mean one company concept automatically covers every subsidiary or product.
Create a free NewsAPI.ai account to test the workflow, or open the NewsAPI.ai documentation to explore additional filters and returned fields.
Frequently asked questions
What is a company news API?
A company news API provides programmatic access to articles about organizations. A basic implementation searches company names as text. An entity-aware implementation resolves the company to a stable identifier and can combine it with language, date, source, category, sentiment and event filters.
Why use entity search instead of a company-name keyword?
Entity search distinguishes the intended organization from other meanings of the same word. It can also connect aliases and cross-language mentions to one company identifier. Keyword search remains useful for products, campaigns and event terms, but it is less reliable as the sole company anchor.
Does this script translate the articles?
No. It retrieves articles in their original languages and stores the original titles and source links. Translation or multilingual summarization can be added as a downstream step.
Can I monitor several companies?
Yes. Resolve each company to its own concept URI and run the same language queries for every organization. Store the company name and concept URI in each row so results remain attributable after they are merged.
Can I track a private company?
Yes, if NewsAPI.ai has a resolvable concept for the organization. If no suitable company concept exists, a carefully designed keyword query may still be necessary. Test ambiguous names manually before using them in an automated monitor.
How do I remove repeated articles?
Use isDuplicateFilter=skipDuplicates to remove records identified as duplicates. Then group remaining records by event_uri when the application needs one item per detected story rather than one item per publisher article.
How often should the monitor run?
The appropriate interval depends on the use case. A daily run can support research and executive briefings. Reputation, risk or market-sensitive monitoring may need shorter intervals and a stored cursor so no newly indexed article is missed.
Methodology and disclosure
This tutorial was prepared by NewsAPI.ai and uses its own API.
The live comparison was run on 12 October 2026 using articles published from 5 through 11 October 2026. It contained ten matched searches: keyword and concept search in English, Spanish, Portuguese, German and French. Each request used news content, newest-first sorting, duplicate filtering and a sample of the latest 50 results.
The reported match totals are not a direct accuracy or coverage comparison because keyword and concept searches use different semantics. The concept-tag overlap measures how many literal-keyword results were also annotated with the exact Meta Platforms concept. It does not prove that every untagged article was irrelevant.
The tutorial script was tested against the live API on 2 November 2026. Product capabilities, allowances and parameters were checked against NewsAPI.ai's public documentation and plans on the same date. Readers should verify current details before deploying a production integration.