GDELT CloudGDELT Cloud
Back to GDELT Cloud
Last updated October 4, 2026

Changelog

Product-meaningful changes to the GDELT Cloud platform. Internal fixes and small refactors are tracked in git; this page covers changes integrators may need to know about.

2026-10-04

Eligible Free accounts can find their unused seven-day plan trial offer throughout the signed-in app and on public pages while signed in. A single clear message highlights API and MCP access with seven days to try free, and links to Subscription to choose a plan.

Monitors is now a direct main-menu link below Situations and above Explore, on desktop and mobile.

2026-10-04

Monitor setup now guides people through a selected company, person, facility, country or region, map area, Event type, news topic or exact Situation. Connected company and facility scopes surface supported published updates, with source coverage shown alongside results.

Run results can be browsed page by page, filtered by update type and downloaded as CSV when export access is available. Connected source coverage is bounded by resolved relationships and source publication; it does not imply a complete history for every company or facility.

2026-10-03

When the plan trial offer is available, eligible Free accounts can choose any public paid plan for a seven-day free trial with a payment method on file. Subscription shows the recurring price and billing deadline before confirmation. The owner can cancel before that deadline to avoid payment; one seven-day extension adds time without refilling the selected plan’s allowances.

Free signup retains 50 QU per month in the web app and API Arena. Existing subscriptions, academic and manual access, grants and earlier evaluation terms are preserved. Trial reporting separates Free signup, trial activation, renewal consent and the first collected subscription payment, with earlier evaluations kept in their own cohort.

2026-10-03

Academic logos on the homepage now scroll right while team logos scroll left, making the two rows easier to distinguish. Hover pause and reduced-motion support are preserved.

2026-10-03

The public website now offers one llms.txt index and Markdown versions of its core product, pricing, data, methodology and trust pages, with discovery links from the HTML pages. These views share the website content and help agents navigate the product and documentation.

Account access guidance explains existing entitlements and usage limits. The privacy policy gives more precise application retention periods and deletion criteria.

2026-10-02

Natural Resources adds shared country, region and continent filters, searchable commodity and statistic suggestions, material filters, and optional full-result observation counts and facets. Original values retain their reference year, source, unit and qualifiers; incompatible measurements are never summed.

Country context includes a bounded mineral-statistics preview and full-result counts where source access is available. The API Arena shows resource measures, facility source observations and participant relationships with their real API receipts. Risk source choices now discover currently ingested publisher lists from the live catalog, including the crawler lane.

2026-10-02

Trial reminders arrive during the final 24 hours, with follow-ups one and seven days after expiry. Emails include measured completed requests, records returned, active days and recorded topics, places, entities and searches. Missing usage remains explicitly unavailable.

Plan guidance includes a recommendation based on observed usage and configured features, the lowest-priced paid alternative, and each plan’s included Monitors. Eligible users with very little complete trial usage can claim one seven-day extension, with current access and usage checked again when they claim.

Free users who keep attempting API access after it ends can receive a weekly recap after the initial follow-ups, only when new attempts exist. Recaps show recorded attempts and, when available, a current sample of matching data.

2026-10-02

Facility reporting-window controls now sit on the left and show visible progress while the requested window reloads. Named Event actors with recognized office titles link to verified person profiles.

Entity detail with registry and exposure access adds recorded parent and child corporate relationships with source evidence. Facility owner overviews show parent-company SEC identifiers and global-list counts separately from the owner’s own records, respecting source entitlements and incomplete coverage. Corporate profile links open in new tabs; MCP get_entity adds the existing include_registry option.

Registry profiles without news coverage retain their exact company Wikipedia identity. Reviewed SEC evidence connects Cursor and SpaceXAI to SpaceX without moving parent records onto the subsidiaries.

2026-10-02

Facility pages now open with a city-scale map, larger reporting-window controls above the summary cards, and prominent source participants. Epoch AI participants are explicitly identified as original Owner and Users records, separate from news actors.

A compact linked-owner overview shows SEC identifiers and global-list counts from the existing entity API, respecting source access and measurement availability. Event cards group unbound same-name references under a preferred profile while preserving unmerged alternatives, distinct resolved identities and the original API references.

2026-10-02

Facility reporting cards now show canonical Story topics, linked Event categories, article sources and actual entity profiles. Descriptive actors remain plain text; ambiguous identities are left unresolved.

Facility context includes linked Story details and per-scope enrichment status through the API, Arena and MCP. Participant profiles fit into responsive columns while retaining their source roles and ownership assertions. Facility search and entity detail also expose bounded source participant-role matches separately from directly owned totals; roles do not flow through corporate parents.

2026-10-02

Facility profiles now show reporting highlights near the top, active reported-owner profile links, and actual source observations and participant roles. Maps, activity cards and facility icons follow the entity-profile theme.

Facility context adds separate reported_owner_matches, reported_owner_events and reported_owner_stories for unique exact reference-name or alias matches. This best-effort reporting preserves ownership uncertainty and its own date coverage; resolved-owner reporting and news-activity rankings retain their existing meanings.

Source observations and participant relationships expose their executed API responses through Use this data. Physical hierarchy links, compute users and reported owners remain distinct evidence.

2026-10-02

Facilities Explore now defaults to News activity (7 days). The API and MCP accept sort=news_activity, ranking the complete filtered directory by direct-owner Event matches first, then the distinct union of owner matches and Events within 25 km. Cards show separate owner and nearby counts, their union and the latest Event date.

The response discloses exact serving dates and unavailable reporting coverage. Nearby reporting is a geographic lead, not evidence of a facility incident; direct-owner matching excludes corporate-parent rollups. Latest directory updates remains a separate sort, and the REST default remains name for compatibility.

2026-10-01

MCP Monitor setup keeps an unsaved draft available when matching is temporarily unavailable, while preserving the failed preview and requiring confirmation before saving. Authentication, plan and quota refusals remain errors.

Monitor drafts disclose whether country filters match Event locations or also actor origins, and distinguish unknown client rendering from unavailable match data. The saved receipt shrinks to its content instead of retaining the form’s empty space. Semantic query drafts require an explicit exact-phrase choice or removal of the text filter before saving; a successful historical preview does not establish saveability.

MCP summary guidance favors category/subcategory and the four core Event metrics. Missing metric means remain unknown instead of becoming zero, and natural-resource results distinguish publisher vintage from GDELT Cloud snapshot dates.

2026-10-01

Facilities now offer a joined reporting view: recorded owners and parents, their Events and linked Stories, plus optional nearby reporting. GET /api/v2/facilities/{facility_id}/context?include=nearby returns the same composite view, with coordinate precision, incomplete owner scope and available reporting dates disclosed.

Facilities Explore defaults to latest directory updates and offers expandable reporting previews, owner links, commodities and source memberships. Nearby reporting is a geographic lead, not evidence of an incident at the facility.

Story entity panels now render the API’s resolved identities, preventing lowercase extraction names from hiding known people and organizations. Explore search controls offer one Hybrid option and explain metric ranges in plain language.

2026-10-01

Added API and MCP contracts for mineral production and reserves, facility observations and relationships, GEM finance, GPU clusters, chip participants and detailed Epoch observations. Availability follows the published source release and is disclosed in response coverage.

Facility releases preserve contributing sources, native capacities, coordinate evidence and participant roles. Ambiguous matches remain explicit, and mines, processing plants, buildings and compute clusters retain distinct physical identities.

Fixed a Facilities query error affecting facility-class filters. Source membership now uses the original records when selecting a canonical facility display name.

Added a REST/MCP workflow guide and selected-release publishers to Data & coverage. Publisher status requires positive publication evidence; geographic coverage is measured by source instead of advertised as a fixed percentage.

2026-09-27

Trial and Free-access campaign messages now check current paid workspace memberships before sending, including customers whose personal workspace remains Free.

Existing subscriptions, organization memberships and grandfathered allowances are preserved.

2026-09-26

New comparison pages cover Bigdata.com, NewsAPI.ai and Seerist with API examples, capability grids and prices for selected workflows.

Explore how Stories, typed Events, entity analytics and connected datasets fit your application, with links to matching Solutions and API Arena requests.

A six-city evaluation shows local news across five continents, with geographic targeting and source-linked examples alongside the comparisons.

2026-09-26

Data & coverage again presents the full picture: Stories, Events, resolved entities, facilities and searchable country counts, alongside measured SEC EDGAR, FRED, GLEIF, USAspending, FARA, V-Dem, limited AIS, AidData, Epoch AI and original-publisher inventories.

Reporting windows and dataset inventories are labeled separately. The API catalog remains a companion reference for endpoints and filters.

2026-09-26

Solution demos now include populated filter comparisons, a connected entity example, a short guide to Stories, Events, entities and facilities, and ready-to-use prompts for your MCP agent.

The usage calculator shows its request breakdown and REST/MCP access requirements. Data & coverage now shows measured public-record and entity counts, source families and dated refresh information.

2026-09-21

Corrected Codex installation commands and VS Code MCP configuration on Connect. Hidden API keys now copy the actual token, and previously created keys without available plaintext cannot be copied as masked text. MCP documentation now explains OAuth sign-in correctly.

Evaluation status failures now show a retry option instead of breaking subscription settings. Workspace changes clear stale evaluation and workspace-label state, and subscription reconciliation reads fresh permissions after an upgrade. Signup preserves passwords exactly as entered.

Pricing now sends new Free users directly to signup and carries the selected paid plan and billing interval into subscription settings. Monitor workflow pages link to the API documentation, and the quickstart reflects signed-webhook access during evaluation.

Serving-window metadata refreshes now finish independently of a successful cached response while retaining their original time limits. The optional API-key middleware lookup now has a short timeout before authoritative authentication continues.

2026-09-21

Background data refreshes can now finish after a page or API request returns cached results. Previously, successful requests could cancel their own refreshes and leave older data in the cache. Query time limits remain unchanged.

2026-09-21

Situations now open in Latest reporting order, matching the API default. Routine data refreshes no longer bring older reporting to the top of the directory. Existing links that request refresh order keep that order and show it as Data refreshed.

The Situation directory no longer requests the map aggregate that its cards do not display. Entity suggestions and all existing search filters remain available.

2026-09-21

Active trials now retain their API access when creating Situations or previewing and running Monitors. Free Monitor previews remain available within the account’s Query Unit allowance after a trial ends.

Query Unit balances consistently include remaining trial and grant credits. Explore browsing has a separate per-user rate limit, so activity from another workspace member does not consume its browsing allowance.

2026-09-18

Public entity, event, story and facility pages now show real, limited data where they used to show blurred "Paid feature" teasers: the top Share-of-Voice sample, recent SEC filings and disclosed relationships, the registry profile's top relationships, connected entities, and the government-exposure, political-offices and AI-compute blocks, on the curated public entity pages.

Every public list is capped at the top five (three for articles, sources and facility owners) and ends with one line saying how many more rows a free account unlocks. The API-view drawer on a public page now registers exactly the request that reproduces the panel, never rows the panel withholds. Signed-in pages are unchanged.

2026-09-18

Published bulk files are now verified weekly, and stale ones re-cut. Until today only the current and previous month were maintained; everything older was written once and never re-read. The first time anything did re-read it, four historical Events files had lost rows — incident adjudication merges events away after the fact, and a merged event leaves the dataset — so those files were serving row sets that no longer matched the API, with checksums that still verified correctly.

A weekly sweep now re-reads every published month, compares it against the warehouse, and republishes any that have drifted, refreshing the summary alongside. If you pin a file by its sha256, expect a historical file to change when its contents genuinely have; the row count and as_of on the downloads page tell you what moved. The full-history Events file keeps its own monthly rebuild and is not touched weekly, so its digest stays stable between those rebuilds.

2026-09-18

Stories are now published as bulk files, alongside Events. One Parquet and one gzipped CSV per calendar month, 37 columns, cut from the same settled table /api/v2/stories serves — so a row in the file and the same row from the API agree field for field. Stories publishes monthly files only; there is no whole-history Stories file. The column dictionary is at docs.gdeltcloud.com/data/bulk-stories-schema.

Two things about the Stories file differ from the Events file and are worth reading before you load one. Its event rollups — linked_event_count, fatalities, civilian_targeting_event_count, linked_event_ids and the has_* flags — are counted over all of a story’s events as of the export, while the API recomputes them under your filters and excludes events merged away since. And there is no country display-name column: country_iso3 carries the country the story is about, using the same attribution-first precedence ?country= and group_by=country use, because the warehouse’s event-derived display name names a different country for some rows.

Every published file now carries a summary of its own contents, expandable per period on the downloads page: the most frequent categories, countries, actors, entities, publishers and languages, with how many distinct values exist and how many rows carry none, plus a full distribution for every metric — count present, min, p10 through p90, max, mean and, where it means something, a total. Quantiles are exact and inclusive-interpolated, the same convention pandas and Excel use, so they reproduce from the file you downloaded. A dash means the metric does not apply to any row in that file; it never means zero.

The downloads page itself is now visible on every plan. The file inventory, coverage, checksums and these summaries are open to anyone signed in — they are how you judge whether the data is worth a plan. Downloading the files remains included with the Intelligence, Enterprise and Academic plans, and the endpoints that issue a download link are unchanged.

2026-09-18

A request for dates before a dataset's coverage begins now answers 400 DATE_OUT_OF_COVERAGE, naming the earliest available date in details.coverage_start, instead of 503 SERVING_SNAPSHOT_UNAVAILABLE with retryable: true and Retry-After: 30. Coverage start was already published on every successful response as meta.coverage.start; a window before it was nevertheless being reported as a snapshot that had not landed yet, which taught clients to retry a request that can never succeed. Measured over one day, 28 of the 40 such 503s were for dates in 2025.

A window that begins before coverage but ends inside it is served from the first covered day. The omission is disclosed in meta.window_adjustment (kind: truncated, reason: requested_dates_precede_coverage, with the omitted dates in held_back_dates), window_complete is false, and meta.coverage.warnings now carries requested_window_partially_precedes_coverage for such a request — previously the warning was judged against the served window and so went quiet in exactly the case it exists for. Pre-coverage dates never appear in coverage.missing_dates, which remains the list of retryable withheld partitions.

Neither change reads the warehouse or the serving tables: the coverage floor is a declared constant, so an out-of-coverage request is refused before any query runs. An in-coverage date whose snapshot is genuinely not ready still answers the retryable 503, unchanged.

2026-09-18

Atlas now opens on the newest day that actually holds records, and names that day on the page, instead of showing 0 Events for the first hours of every UTC day. Events are coded after the events themselves, so the current UTC day fills in over the following hours; asking for it by name returned an empty-but-successful reading. Opening /atlas without a date is now read as a request for the most recent data, and the chip above the map says which day is being shown.

The same correction reaches the API. A relative window — ?days=N, ?window=, or any request that does not name a date — whose end date holds no records yet now anchors to the newest day that does, keeping the requested span and disclosing the move in meta.window_adjustment (kind: anchored, reason: current_date_snapshot_not_ready). Previously such a request returned 200 with no rows. A window that names its dates explicitly is unchanged: it is still served literally, with its bounds and window_complete exactly as before.

New response field: meta.coverage.awaiting_dates lists dates inside the served range that hold no records yet. They are neither zero-count days nor withheld partitions, and no bucket is emitted for them — so a date still filling in is no longer indistinguishable from a day we measured as quiet.

/api/v2/entities follows the same rule, with one difference worth knowing: it reads the resolved entity layer rather than a settled partition, and that layer reaches a new UTC day at roughly 01:20-03:20. A relative window ending on a day the layer has not reached now serves the newest day it holds. The move is reported through applied_filters.date_start/date_end, which this endpoint already echoes so callers can see which window produced the counts; it carries no meta.window_adjustment because the entities list emits no meta envelope. An explicit window, a historical window and a recorded interval are all unchanged and never slide.

Two consequences worth planning for. A relative window that anchors carries window_complete: false, so its response is not cached; and a paginated walk over a relative window can meet CURSOR_STALE once a day, at the moment the current date’s first records land — restart from the first page. Callers that poll a relative window to detect whether a day has landed should read meta.query_window.date_end rather than inferring it from an empty result.

2026-09-15

Events and Stories lists and summaries now answer a request that can only mean one thing instead of refusing it: a parameter name sent in a different case or spelling, a widely used synonym for a date window or page size, a value that restates what the endpoint already does, a limit above the maximum (served at the maximum, with pagination.next_cursor), and a date window longer than 30 days (served as its most recent 30 days). Every change is listed in the new applied_filters.normalized field. Anything ambiguous is still refused with the same error as before.

An explicit entity_match=material or entity_match=actor on these endpoints is now served as entity_match=coverage and flagged with applied_filters.coverage_fallback_applied: true. Coverage returns every row mentioning or linking the entity; it does not establish actor participation or material involvement.

meta.window_adjustment.reason gains the value window_exceeds_maximum, with max_window_days, when a window was shortened to the maximum span, and meta.coverage.window_complete is false in that case. A request carrying ?constructor= or ?__proto__= now answers 400 UNKNOWN_PARAM instead of 500.

2026-09-15

Fixed — following pagination.next_cursor on /api/v2/events and /api/v2/stories no longer fails with CURSOR_STALE on the next page when the published data has not changed. A cached first page could come from an older published snapshot than the one the next page was checked against, so a walk could be refused on page two seconds after page one, and that first page could be several hours behind the latest published data.

First pages now reflect the current published snapshot within seconds. A cursor is refused only when the snapshot really changed between pages; restart from the first page in that case.

2026-09-14

Events and Stories requests now return every safely published date in a valid range when another requested date is not available, including a future end date or a historical partition gap. Coverage metadata names the exact served and missing dates and whether the window is complete; missing dates are never presented as zero-count buckets. If no requested date can be answered safely, the API returns a retryable snapshot error with the target and date.

Withdrawn Events no longer remain visible through Story links, linked-event counts, or event-derived geography. Publication records the affected serving partitions for repair through the normal settle workflow.

After the confirmed Free-access notice deadline, scheduled Monitor execution follows the same access lifecycle as API and MCP access. Free retains the web app, API Arena, 50 Query Units a month, saved Monitor settings and Monitor previews. Active evaluations and the claimable cutoff offer keep their promised daily Monitor allowance.

2026-09-13

Preview behind a rollout flag: retained Situation editions add brief, structure, context and independently paginated frozen evidence. Briefs distinguish reporting from assessment and conditional outlooks; unavailable analysis remains explicit. The grouped graph preserves Story, Event and Entity identities while expanding threads locally. Complete history begins when retention is enabled; earlier clipped previews are not reconstructed.

2026-09-13

GPR and Posture maps select and zoom directly to countries. GPR maps disclose eligible low-count daily estimates separately from seven-day tension share.

2026-09-13

Explore evaluations include 1,000 total Query Units for 7 days, with one optional 7-day extension after sharing the intended workflow. They include every generally available data endpoint, the full web UI, REST API, MCP, and up to 3 daily Monitors with email or signed webhooks. Bulk downloads remain outside the evaluation.

After the evaluation, Free keeps the web app, API Arena, 50 Query Units a month, saved Monitor settings and Monitor previews. API keys, OAuth, MCP, scheduled Monitor execution, Monitor webhooks and bulk downloads require active access.

2026-09-12

Choose a team on the homepage to explore an energy-desk watchlist with a Brent benchmark, named steel-plant incidents mapped to registry assets, regional security reporting connected to Situations, corporate publisher records, or a typed trade and technology feed. Publisher images, classifications and metrics accompany real API receipts; the selected feed continues in the API Arena or a Monitor.

All five choices load from verified snapshots, including on a cold deployment or a data-service outage. Scheduled refreshes publish new results twice daily and retain the last successful evidence on failure. The capture window is 24 hours; original event dates, registry vintages and benchmark periods remain explicit. Public records support investigation, not a compliance decision.

2026-09-12

Entity Dossier now includes the publisher records projected by our self-operated OpenSanctions ingest. Records retain distinct categories, including sanctions, export controls, debarment, combined screening lists and military affiliations; each timeline receipt carries its publisher attribution, evidence link, listing or observation date, and source refresh date. The response returns one canonical entity id and separate Event and Story counts for the requested window.

The legacy sanctions_lists field now counts sanctions and export-control sources only. Use summary.public_records for the full publisher-record mix. Combined CSL screening records and DoD 1260H military affiliations are no longer presented as sanctions. The source records remain available; existing cached exposure rollups adopt the correction on rebuild.

Signed-in browsing and active Explore evaluations can use the dossier without an accidental plan block. Situation handoffs now retain the dossier reporting window, and a Monitor started from an entity-filtered Situation view retains the entity instead of broadening silently.

2026-09-12

Event titles now preserve the coder-recorded title choice through the serving snapshot, including specific incident titles that end with their coded location. Situation and Event views therefore keep the Event-level title instead of replacing it with a broader Story headline.

Country shapes in Atlas Today, GPR and Posture now open a shared country panel with a protected new-tab link to the country page. GPR and Posture keep their existing continent, region and country drill navigation while the selected country remains available in the panel.

2026-09-11

The hourly catch-up pass that codes Stories the main pipeline left without an Event no longer creates duplicate Events. It now checks each coded record against the Events already stored before it creates one, with the same matching the main pipeline applies. A record describing an existing Event links its Story to that Event, adding to its observation count and sources, instead of creating a copy; a record dated more than a day before the Story it came from creates no Event, as in the main pipeline.

Records the matcher cannot decide are still created, so coverage does not drop. Duplicates created before this change are not removed by it.

2026-09-10

The public publisher profile pages and their embeddable cards have been retired. They were built entirely from the GDELT GEG feed, which stopped publishing on 2026-06-18, so since June they showed a frozen snapshot rather than current coverage. Old links now redirect to the Sources & coverage section of the Data page, and /api/public/domain and /api/embed/domain-card answer 410 Gone.

2026-09-10

Public entity, event and story pages, and the shared data behind them, now refresh twice a day for anonymous visitors instead of hourly. Signed-in readers and API callers are unaffected and continue to receive the freshest available data.

Public Situation daily editions now show the top Stories, Events, Connections and entities by coverage, with the full totals in the header and a link to the complete live Situation for signed-in readers. Edition pages and the Connected Situations index read their published editions from a twice-daily cache.

2026-09-10

Requests that ask for a relative window — days=, window=, or no date parameters at all — no longer fail at UTC midnight. A relative window names a length and lets us choose the dates, so when the current day has not finished settling we now serve the most recent day that has, keeping the span you asked for, instead of returning 503 SERVING_SNAPSHOT_UNAVAILABLE. days=1 sent shortly after 00:00 UTC was the common case and returned an error for as long as the first settle of the day took.

The window actually served is always reported in meta.query_window, and meta.window_adjustment names the requested and effective windows. Coverage metadata names exact served and missing dates. An explicit window — date_start/date_end, or date — is never moved: every published date is returned, unavailable dates are disclosed, and the request is refused only if no part can be served safely.

2026-09-09

Reads of the reference layer — the entity registry, identifier crosswalks, office holders and screening-list memberships — are cached on their own schedule instead of being discarded every time the event pipeline publishes. That layer is rewritten at most daily, so it was being re-queried roughly forty-eight times a day for data that had not changed, and each of those reads is an expensive whole-table pass.

Nothing about freshness changes for events, stories or any other pipeline output. An entity merge still invalidates the affected reference reads immediately; a newly crawled register appears within six hours rather than within the hour. Reads that combine reference and pipeline tables keep the pipeline schedule, so a request can never receive a stale event alongside a fresh identity.

2026-09-09

Public daily editions of Country and Situation pages now publish. The lane that freezes one completed UTC day per page had never produced a single edition since it shipped: its readiness check aliased a projected column to the name it also filtered on, which ClickHouse resolves to the alias, so the check raised a type error on every call and every build was abandoned. The Situation half additionally composed a lease identifier the coordination function refuses, so it stopped before reading its first candidate.

For readers this means a public Country or Situation page serves a complete, stable day rather than reconstructing a partial one on each visit. Signed-in readers and API callers are unaffected and continue to receive the freshest available data. Editions cover only days whose serving inputs finished settling after the day ended, so a day still in progress is never frozen.

2026-09-09

Situations are de-duplicated every six hours instead of once a day. Situations are created at every hourly maintenance window, so a daily collapse pass could leave two Situations covering the same occurrence listed side by side for up to a day; the interval between de-duplication passes now bounds how long that can last.

The collapse pass also no longer depends on the earlier expansion stages succeeding. A failure while extending existing Situations previously cancelled de-duplication for that window, so a bad hour both created the duplicates and skipped the pass that removes them. Each stage now reports its own outcome independently.

2026-09-08

Atlas Today follows Events, shows all directed country pairs with an Edges on/off control, and highlights the countries holding each Event metric maximum with metric icons and supporting evidence. Country hover cards include Stories and linked identities; selecting a continent, region or country fits the map. Regional macro panels use comparable observation periods and show their country coverage.

Country context gains stored daily exchange rates, monthly inflation, quarterly GDP, quarterly European government debt, unemployment, net migration and age cohorts alongside annual World Bank indicators. Observation periods, source vintages and retrieval dates remain distinct. Missing measurements stay unavailable; central and general government debt remain separate.

Situations gains a newest-created sort, map connections, and a Graph view with clear reporting-window controls and unobstructed nodes. The homepage and Situations overview show the product visually. Country Events, Stories and Entities use ten-row pages; public officials can be browsed alphabetically without a name query, and office evidence no longer presents ingestion dates as publication dates.

Query Monitor setup previews for Events, Stories and Entities now show historical reporting-date matches through the same public list endpoints. Seven- and thirty-day examples are labelled as estimates, not recorded additions or notification replay, so newly initialized publication history no longer prevents this setup step. Scheduled matching still uses exact recorded intervals and requires available publication history; partial examples cannot establish quiet days.

The sidebar adds an Atlas view menu, puts Plugins and Connect first under Use the data, and restores Agent below API Arena.

Data source pages show each new provider’s ingest cadence and whether it runs on Vercel or GitHub Actions. The admin ingest monitor shows provider outcomes, observation dates and initial-load status; compare runs and unrelated shared-table writes cannot establish feed freshness.

2026-09-08

Atlas Today now shares the GPR instrument: the same header, a continent → region → country rail, the draggable 31-day time machine, a metric strip, and arrows coloured by Event count with a visual hover. Entity pages read their 30-day media tone again (a 31-day request was being refused as too wide). Every Explore tab, Situations discovery and each Situation carry one compact action group — Monitor this and Use this data — and Situations discovery gains Recent / Most Stories / Longest sorts on a borderless map.

Situation pages group their window details behind closed sections, open every evidence link in a new tab, and end with the methodology; Story pages show the top three articles and sources by the ranking the API already uses. The sidebar links the API Arena and Bulk Data Download under Use the data.

2026-09-08

Settings carries a Danger zone: you can delete your own account. It removes the account, the personal workspace and everything keyed on it (API keys, Monitors, Briefs, usage history, unclaimed credits) and drops the address from our mailing list. Team organizations you own must be transferred or deleted first, and an active subscription must be cancelled first, so a deletion can never orphan a team or leave a subscription billing.

2026-09-08

Existing Free accounts receive at least 48 hours of email notice before API keys, OAuth, MCP and Monitor execution require a paid plan, active evaluation or active credit offer. The confirmed deadline appears in the account; the cutoff does not start with deployment. Evaluations keep their promised access and paid plans are unchanged.

The web app, API Arena, 50 QU a month and saved keys and Monitors remain available. Eligible existing personal Free workspaces can activate 500 QU at /claim/free-programmatic-cutoff, with API + MCP and up to 3 daily Monitors for 7 days from activation. Your claim page shows the activation deadline. Reply to hello@gdeltcloud.com if this affects something you are building.

2026-09-08

Situations have a public home at /connected-situations and their own Situations section in the API reference (the seven operations moved from Stories; old links redirect). The OpenAPI spec now declares the 409, 422 and 503 responses Situation paging, Situation creation and query-Monitor creation raise. Docs add the POST /api/v2/situations worked example with its Idempotency-Key, a Python paging walk with scope_version, an /api/v2/activity cursor walk, the political-offices endpoints, and the Countries basis and directory recipes.

MCP and plugin release: regenerated contract, skill descriptions naming Situations, Countries, activity, offices and query Monitors, plugin 0.5.0.

2026-09-08

The Data status page's daily and hourly Core API latency charts now measure successful API-key requests. Fast authentication rejections and failed requests no longer distort the p50 and p95; the chart explains which requests it measures.

Monitor run matches and CSV exports now fetch current cards from the same published snapshots as the Core API, avoiding repeated warehouse-query timeouts while preserving the original match list and change statuses. Unavailable snapshots return a retryable error.

Event snapshot refreshes now fetch provenance in bounded batches, preventing large event days from exceeding ClickHouse's query-size limit.

2026-09-07

Explore starts with Stories and adds an Atlas-style Countries map with a searchable, paginated directory, including quiet countries. Map activity covers the full filtered country set independently of the list page. Atlas Today opens on distinct coded Event activity for the current UTC day. Reporting, Stories and publication additions retain separate labels and dates.

Country selections retain geographic filters across Explore and Monitor handoffs. Historical single-country activity avoids duplicate global aggregation, and temporary source failures remain explicit. Entity source labels explain their coverage; Situation detail reads tolerate pending optional schema additions.

Country pages put compact activity over an edge-to-edge Atlas map, with Overview, Activity, Situations, Economy & Resources, Facilities, and People & Offices. Facility and office filters retain separate pagination; facility markers represent the sites on the current results page. Dated economic units and vintages remain separate from reporting dates and office as-of queries. Public officials retain person identity and gain one shared evidence-backed badge; office pages describe the office and its holder history.

Situations add canonical entity and Story/Event discovery, category summaries, latest-development ordering, a Map/Graph toggle and independent 25-row evidence pages. Full Connections lists retain membership decisions and provenance even when the graph is sampled.

Public Countries and Situations use immutable daily editions with cutoff and publication times; signed-in views stay live. Failed publication retains the previous edition. Hourly Situation maintenance has bounded progress, seven-day inactivity archival, adjudicated reactivation of the same identity, and measured model usage and cost receipts.

Paid subscribers and active trial users can create or expand a shared Situation for 5 QU. Existing canonical reuse costs 0 QU. Event seeds require explicit Story selection when ambiguous, and idempotent requests reserve or refund quota without duplicate retry charges.

Query Monitors match newly committed records since the previous successful checkpoint, including late arrivals. First enablement starts without delivering preview history; 7-day and 30-day previews are separate. Expired Free accounts retain signed-in browsing with QU after the trial and optional extension, while programmatic REST/OAuth/MCP, Monitor execution and exports require subscription. Saved keys and Monitor settings are retained.

Monitor this uses one prominent shared control, with human-readable entity names in prepared drafts. Each page has one Use this data entry point. Display decoding preserves non-Western scripts and recovers truncated encoded Story labels from complete stored titles where available.

2026-09-06

Entity discovery uses the canonical lexical candidate endpoint. Explicit strict country association excludes unknown evidence; existing requests without country_match retain compatibility. Facility candidates retain facility_id, source records retain nullable entity IDs, and failed reporting coverage remains unknown. Candidate guidance is aligned across Arena, MCP and plugins.

Stored Situation Story/article/Event totals measure full servable membership independently of graph limits. Stories and Events have dedicated paginated readers. Situation detail groups evidence into Overview, Stories, Events, Entities and Connections.

Atlas Today adds UTC-day publication activity, hourly country views and evidenced actor-to-target connections. Country pages group activity, economy and resources, facilities, and people and offices, with source periods and unavailable coverage shown explicitly. The data directory unifies sources and distinguishes identity types from political roles.

Quiet countries can retain annual-context Posture scores marked Best effort. Low-count GPR estimates are separately qualified and keep the official reading withheld; absent observations remain unavailable. Selected dates, component evidence and API View agree.

Home carries selected identities and filters into reporting, API requests and query-backed Monitors. Setup includes a 30-day historical estimate and explicit saving and activation. API View retains executed requests and candidate lookup receipts; query Monitor results distinguish observed publications from complete source history.

Situation advancement and discovery are scheduled hourly with the existing daily seeding budget; reconciliation and merging run overnight. Errors and deadline exhaustion are reported as incomplete runs. Prices and entitlement policies remain unchanged.

2026-09-06

Restored the main sidebar as a translucent overlay. Expanding it no longer shifts or resizes Atlas or other authenticated content; the desktop content keeps its fixed rail clearance.

2026-09-06

Data & coverage (/data) now counts in one vocabulary: records are what a source publishes (a list entry, a roster line) and entities are the registry's one-per-party rows, so the top tiles carry both numbers separately — records held from crawled sources, and entities in the registry — and a definitions block plus hover/focus hints on every column header say what each column counts. The entity database is shown by the API's own kinds (the `type` values), and a source with two loaders (SEC EDGAR, Global Energy Monitor) is one row.

Sources: our curated regional news outlets are now a row of their own under News and media inputs, with outlets by region, country and language derived from the ingest registry and, measured on the served Stories, the share of the last 30 days' Stories that carry one of them; registers, lists and rosters that run on our own scheduler moved out of the news group. Coverage by country opens on demand like the other sections.

2026-09-06

Core Search → Entities has an "Office holders" toggle beside the person/organization type filter. On, the page sends the documented role filter — GET /api/v2/search?universe=osint&holds_office=true&q=<name> — and each hit shows the office held today (current_office: name and country) exactly as the API returns it. Office-holders are people, not a third entity type; the toggle follows the API's own plan gate, so without can_use_offices the API answers 403 PLAN_REQUIRED and the page shows that.

2026-09-05

Home now uses one focused Events, Stories or company query panel, with topic and date controls and a direct route to advanced geographic filters. API/MCP connections, saved Watch workflows, published Events files and specialist maritime/energy data remain easy to reach. Atlas and Situations stay visible.

Home, API, Watch and Data share a refined workspace layout that adapts to mobile and the open API drawer. API recipes expand individually, and Watch puts recorded Monitors before setup choices. These presentation changes preserve existing APIs, plans, prices and access rules.

2026-09-05

Home now runs company, country-reporting and coded-Event searches inline. Use this data exposes the real request beside results on wide screens; reporting links retain the entity, dates and supported filters. Monitor handoffs prepare a reviewed draft and disclose rolling-window or unsupported-filter differences before execution.

Semantic and name-search candidates now receive the shared serving filters before ranking, preventing country-scoped false empties at small page sizes. Filter edits clear stale aliases and pagination, and controls display applied values even when their menu uses a different label.

Source access links retain the current work and identify eligible plans from the live catalog and effective organization permissions. Checkout and cancellation preserve the return link. Existing prices, billing periods, trials, Query Units and access rules are unchanged.

Signed-in Data and public Data & coverage now share one source inventory and measured snapshot. Published Events files remain the available bulk download; reference datasets are not advertised as new exports.

Company reconciliation now supplies original registry evidence to the existing independent judge and can propose already-bound aliases across source families. Article attribution has a bounded observation stage and a separately enabled persisted enforcement path; this does not repair historical identities or assert that all current article links have been verified.

2026-09-05

Office-holder search (GET /api/v2/search?universe=osint&holds_office=true) now matches the person's registry name as well as the roster's own spelling, and accepts a surname-first query — so "Keir Starmer" finds a roster row published as "Starmer, Sir Keir". Bound results now carry the registry's display name.

2026-09-05

One Data & coverage page at /data: coverage by country (Events, Stories, registry entities and office-holders in the last 30 days), the entity database and its enrichment layers, politicians with a world map, every source with its status and licence, and the dataset reference with known limitations — each a collapsible section. /data/sources redirects there.

Sources are grouped as news inputs versus registers, lists and rosters, with how we obtain each (feed, published file, crawled) on the row; the record and entity columns are named for what they count.

2026-09-05

Office summaries now aggregate the returned term statuses correctly and refuse failed counts instead of fabricating zeros. Linked office records preserve partial date precision in the API and Situation context.

A focused workspace starts with subject search and saved monitoring work. Data, API and Watch bring existing capabilities together; Atlas and Situations remain directly accessible. Existing plans, prices, Query Units and source permissions are unchanged.

Situations now has a compact search interface with Event location and category filters. Cards report linked entity counts across current served membership; a paginated entity endpoint and browser expose those identities with supporting Stories and explicit missing-registry status. Timeline and entity-page JSON downloads preserve their separate scopes. Invalid category responses now honor the documented enum error code.

2026-09-05

Situations now has a searchable directory and a reporting timeline with member explanations, linked coded Events, and on-demand entity context. Date-scoped pages, API View and JSON view downloads use the same public response. Existing plans and Query Unit allowances apply; this release exposes read workflows and keeps creation and expansion out of the customer interface.

Situation date filters now run before member limits. Recorded membership decisions are distinguished from chronology, missing Event counts remain unknown, and truncated views disclose their bounds. Offices and list context follow the existing source permissions.

Entity dossiers now distinguish coded Events from clustered Stories. Facility context preserves typed ownership paths and percentages instead of selecting one minority parent; unavailable reads are no longer represented as zero. Facility projection retains native capacity when available.

2026-09-05

One entity per politician: a person minted from a parliament or government roster is now merged into the news entity that already carries their Wikipedia article, when an independent judge shown the offices, dates, constituency and birth year agrees. Search returns one Ted Cruz, and the office scope on Events and Stories (office=) reaches the news attributed to the office's holders.

Merges are reversible from the merge ledger; namesakes stay apart by default (the economist Adam Smith and the singer Al Green keep their own entities).

2026-09-05

New page: Politicians & offices (/politicians, early access on the political-offices flag). Pick a country and an as-of date and see who held which office on that date, as published by parliaments, governments and Wikidata; open an office for every holder on record, the holder(s) on the chosen date, and the Events and Stories attributed to those holders in the 30 days to that date. The page is three API calls shown verbatim: /api/v2/offices, /api/v2/offices/{id}/holders with as_of, and /api/v2/events and /api/v2/stories scoped with office= and office_as_of=.

Screening and sanctions parties are now deduplicated across registers: the same designation mirrored on several national lists resolves to one entity, and searches and entity pages no longer show one copy per list. Every merge is recorded and reversible.

2026-09-05

The Stories list and summary remain available when a new UTC day is correctly empty. A bounded source check still proves the empty day; the API no longer requires an impossible physical Story–Event link row from a zero-row projection.

When the first source Stories arrive before their first serving refresh, default rolling queries temporarily hold at the latest complete snapshot instead of taking the Stories API down. An explicit request for the unpublished date still returns a retryable error, and no request rebuilds from the warehouse.

2026-09-04

Entity directory: `GET /api/v2/entities?sort=recent` now breaks same-day ties by candidate mention and article volume before identity. The day-grained ordering that shipped earlier today tied every entity active on the latest day and fell through to the name tiebreak, so a "most recent" page — in the API and in the Arena — listed one-mention entities in alphabetical order. The news-activity day still leads, registry and link-processing times still never do, and cursor pages remain fixed candidate pages that resolved counts do not reorder.

2026-09-04

New public page: the source directory at gdeltcloud.com/data/sources lists every source behind the API, one row per source — the publisher, its country, what it contributes, the update cadence, the licence, the endpoint group that serves it, and whether we hold rows for it today. It sits under the existing dataset-level reference at /data, which keeps the coverage windows and the known limitations of each dataset.

The crawler lane is disclosed in full: several hundred official publishers — sanctions authorities, regulators, parliaments, courts and multilateral bodies — each linking to that publisher's own page, because that is where we fetch it from. The page credits OpenSanctions for the cataloguing work and for the MIT-licensed crawlers we fork, and states plainly that their compiled CC-BY-NC dataset is not an input and is never redistributed.

No row carries a record count. A source shows as live only where rows are measured in our own tables and as catalogued otherwise; an unknown country or licence prints as blank rather than as a fabricated value.

2026-09-04

Screening: the hand-loaded restricted-party list lane is superseded by the OSINT crawler lane, and every legacy `list=` value now has a named successor. `GET /api/v2/lists` carries `superseded_by` per source (e.g. `csl_ofac_sdn` → `os_us_ofac_sdn`; the five `csl_ofac_*` sub-lists → `os_us_ofac_cons`; BIS Entity/MEU/UVL and State ISN → `os_us_trade_csl`) and `retired_at` once a legacy source has been cut over.

Deprecation, effective per source once its successor is ingested: a legacy `list=` / `source=` value on `/api/v2/lists`, `/api/v2/lists/entries`, `/api/v2/lists/changes` and `/api/v2/exposure` resolves to its successor, `applied_filters.list` names the successor, and `applied_filters.deprecations[]` names the legacy value, the successor, the announcement date and the earliest removal date. Until the successor is ingested the legacy value keeps answering from the legacy rows with no notice. Where the successor is a consolidated list (OFAC non-SDN programmes, the CSL) the alias is WIDER than the legacy sub-list and the notice says so; narrow with `program=` on `/api/v2/lists/entries`.

Notice period: legacy values are accepted until at least 30 days after this announcement and never sooner than 30 days after a source's cutover is announced here. On the cutover day a legacy source's entries become inactive and `/api/v2/lists/changes` records them as `removed` beside the successor's `added` rows — that is the actual event and it is not hidden. The full inventory is on the API stability page. Two declared-but-never-ingested keys, `sec_hfcaa` and `mofcom_uel`, are removed (no successor; they never answered a request).

2026-09-04

The Entity directory now orders recent results by dated news activity across its entity sources, retains stable cursor pages, and no longer presents registry or link-processing updates as recent news.

Failed Story, article, mention or Event count reads now appear as unavailable rather than zero. Explicit name searches retain known entities with measured-zero coverage; the activity directory omits them and explains short pages.

Entity type filters apply the shared source-vocabulary map before display, and directory cards label news dates without an invented minute-level timestamp.

Event pages now display the same bounded Story links as the API, preserve incident-member links, and show unavailable reads honestly; Story pages retain details when a linked Event resolves to its canonical ID.

2026-09-04

Entity admission reviews now inspect the saved Wikipedia article in its original language and use its short description alongside the opening paragraph. This restores the existing surname-page rejection and gives identity review the evidence from the actual linked page.

2026-09-04

Entity detail count failures now return null for unavailable measurements while retaining known counts and linked cards. Pages and source indicators distinguish unavailable coverage from measured zero. Entity activity lists publish their exact UTC date window and label any expansion to include older activity; the one-day option is labeled Today UTC.

2026-09-04

Story membership refreshes now resolve only the canonical Event identities needed for duplicate selection, avoiding unused Event-card joins that could stall publication. Existing date boundaries, duplicate rules and publication checks are preserved; failed membership reads are not immediately repeated.

2026-09-04

Published Story–Event link refreshes now expire cached responses and linked-event rollups, even when Story card timestamps remain unchanged.

2026-09-04

Query corrections now rank whole-word category matches first, offer the complete category union for broader groups such as Political violence, and identify the supplied date parameter and exact requested day count on oversized-window errors. Inclusive date ranges and exclusive observed-time ranges retain their existing limits. Summary guidance uses date chunks without recommending unsupported cursors.

2026-09-04

Failed or refused API, Arena, MCP and on-demand Monitor queries now return their reserved Query Units and trial credits exactly once. Explore quota errors show the evaluation balance and expiry separately from monthly limits.

Monitor Preview and Run now cancel queries at a bounded deadline, show elapsed progress, and distinguish an empty window, already-seen matches, unavailable history, and expired retained evidence. Empty manual runs can show separately labelled historical examples.

Plan errors name the required capability and available alternatives. Arena tool access follows effective endpoint entitlements; Atlas and navigation link directly to API keys and first-call setup.

The API Arena now gates each catalog operation using its actual account capability and starts GPR requests with the supported seven-day default.

MCP tools preserve REST date-error details and retry guidance. Symbol Search accepts the query alias, while unsupported days parameters explain outputsize without changing their meaning.

Usage diagnostics retain row-source reasons, structured errors, and redacted Monitor and MCP arguments. Plan, quota and disabled-key refusals retain the correction and recovery guidance returned to the caller. Webhook delivery tests no longer report an invented result-row count.

Invalid Events modes and time windows return guidance before any data lookup. Disabled-key refusals retain their edge protection and record an attributed zero-QU audit.

2026-09-04

Entity search now checks exact ticker identifiers before name and acronym matches, and all entity sources publish scores on one relevance ladder. Multiple registered companies sharing a ticker remain separate candidates.

Story and Event name matching now folds accents on both the query and stored text. Boolean-shaped search inputs strip grouping parentheses from the single term actually searched, while continuing to disclose ignored terms.

Story name searches retain their literal-match candidate set when country, language or category filters narrow it, so adding a filter cannot replace one named result with unrelated semantic neighbors. Search responses no longer claim that names are absent when a lexical lookup failed. Empty entity lists explain whether identity resolution found candidates, found no recognized match, or was unavailable.

2026-09-04

Core lists and summaries now disclose the effective date and observed-time predicates in meta.query_window, separately from corpus coverage. Oversized windows include coverage and valid date chunks; list endpoints also explain cursor pagination. Category filters accept case variants, and invalid city, family, Story-topic, and disorder-type filters point to supported calls. /events/count now points directly to /events/summary.

Date-window schemas no longer suggest days=2 as equivalent to omission: Core defaults remain 24 hours or 30 days for entity filters, while Entity discovery retains its 30-day coverage window. MCP tool descriptions share the API guidance on coverage starts, date chunks, and supported pagination.

2026-09-04

Entity-filtered Events and Stories now default to supported coverage matching. Coverage identifies Stories mentioning or linking an entity and their Events; it does not establish actor participation or material involvement. The unavailable material and actor modes have been removed from public controls and documentation. Explicit requests for either return a nonretryable 400 with entity_match=coverage guidance.

2026-09-04

Queries that exceed their database execution limit now return QUERY_TIMEOUT (503) with Retry-After guidance without immediately repeating the same timed-out statement. Historical list and summary requests also return an explicit snapshot-unavailable response when a required serving date is missing.

2026-09-04

Story refreshes now hydrate bounded groups through the same detail query and card mapping, reducing repeated database work while preserving Story scope, duplicate rules, retry progress and atomic publication checks.

2026-09-04

Story refreshes now resume unfinished work across bounded settlement runs, preserving completed Story updates while keeping freshness timestamps honest until the remaining work is finished.

2026-09-04

Added a guarded recovery path for retained original entity evidence behind September 2 Stories. Recovery preserves original article records and existing event links, and validates current Story memberships before publishing restored cluster links; complete daily coverage and subsequent Story settlement are checked separately.

2026-09-04

Hardened ingest completion reporting and refresh publication against invalid Unicode in diagnostic metadata, so completed event coding can finish publishing without repeating paid work.

2026-09-04

Historical Story snapshots can now recover list membership without reprocessing existing Story cards. Repairs preserve card data and original freshness timestamps, apply the canonical duplicate rules, and verify the full snapshot before publication. Published Story refreshes immediately expire cached responses, including when pending card updates require retaining an older freshness watermark.

2026-09-04

Story refreshes now preserve current list membership for refreshed and unchanged Stories, including Crime Stories without linked Events. Membership is recomputed using the existing duplicate rules before publication, and refreshes read current ingest data instead of copying their previous snapshots.

2026-09-04

Fixed Story-category filters on GET /api/v2/stories. Since September 1, settled list requests could return unrelated categories while reporting the requested filter as applied. Single and multiple Story categories now constrain both candidate selection and returned rows, including subsequent pages.

Daily Crime feeds should use story_category=cameoplus_crime and follow pagination.next_cursor. category=CRIME filters linked Crime Events and is narrower: it excludes Crime Stories without a coded Event.

2026-09-04

Story article evidence and public Story pages now restrict article joins to the requested Story and dates, reducing database memory pressure during concurrent requests without changing article filters or pagination.

2026-09-04

Expanded UTC-rollover protection to missing earlier dates and Story links within current-day requests. Events snapshot failures now return a retryable 503 without retrying against the warehouse, preserving capacity for recovery.

2026-09-04

Story refreshes now share one execution budget, leaving time to publish results and refresh delayed historical dates.

2026-09-04

Reduced Event enrichment and ingest cleanup work to improve reliability under load.

At UTC rollover, requests whose current-day snapshot is unavailable return retryable SERVING_SNAPSHOT_UNAVAILABLE (503, Retry-After: 30) instead of triggering costly fallback reads. A verified empty day retains its explicit snapshot timestamp.

2026-09-03

New — political offices and office-holders. GET /api/v2/offices searches public offices — legislative seats, cabinet posts, heads of state and government, courts, security and financial offices, IGO posts — one row per office with holder counts; GET /api/v2/offices/{office_id}/holders is the roster of who held it, and GET /api/v2/entities/{entity_id}/offices lists every office one entity has held. `as_of` on all three is VALID time — who held the office on that date, from the start and end dates the publisher states — and an office-holder with no published start date is excluded from a dated question rather than guessed. The endpoints are live and gated on `can_use_offices` and are demoed in the API Arena; they appear in the reference documentation once the first load report publishes measured coverage.

New — `office=` on GET /api/v2/events, /api/v2/stories and both summaries scopes the request to the office-holders of a political office, in the same way `entity=` scopes it to one actor; `office_as_of=` narrows the roster to whoever held the office on a date. Matched rows carry `entity_link.via: "office"` naming the holder, and `applied_filters.office_holders` reports how many of the roster could be scoped — holders reach the news layer only through a Wikipedia identity, so the counts are a floor. A roster too large to scope answers 400 OFFICE_SCOPE_TOO_LARGE rather than a truncated 200.

Changed — restricted-party lists now include natural persons. A person row on GET /api/v2/lists/entries and in a GET /api/v2/screening/match hit carries exactly this field list: name, aliases, citizenship, Wikidata QID, gender and birth year. It never carries a full date of birth, an identity-document number or an address, whatever the source publishes. GET /api/v2/lists reports `includes_individuals` per source so a person screen can be scoped to the sources that publish people.

Changed — GET /api/v2/lists carries a `category` per source (sanctions, export_control, debarment, wanted, maritime, domestic_terror) and accepts `category=` as a filter. Only sanctions and export-control memberships count toward the sanctions exposure lens; a debarment or wanted-persons listing is catalogued and screenable but is not a sanction.

Every offices response and every list response is actor context for geopolitical-intelligence analysis — not a sanctions-screening, KYC/AML or compliance control, and never a compliance determination. Use a compliance-grade provider for screening decisions.

2026-09-03

Fixed — GET /api/v2/events/summary?group_by=subcategory returned 500 INTERNAL_ERROR after about 94 seconds on multi-day windows, and did so non-deterministically: the same request could fail and then succeed. Seven of the CAMEO+ domains were affected; `category=INFORMATION` and `category=TECHNOLOGY` failed most often. It now answers in well under a second.

Cause: `subcategory` was the one summary dimension excluded from the serving tables, so it alone fell back to the live warehouse join — measured at 22.5 million rows and 21.7 s unfiltered, and 106.9 s with a category filter, against 35.8 thousand rows and 0.1 s from the serving table. That exceeded the statement ceiling, was retried as transient load, and surfaced as a slow 500.

The buckets are unchanged where they were retrievable at all: over a settled week the two paths return the same 267 buckets and the same 11,950 events, and `group_by=subcategory` still reconciles to the same total as `group_by=category` and every other dimension. One bucket does disappear — a raw, undeclared coder code that was being published as though it were a taxonomy value. The events list has never published those, and the summary no longer does either.

2026-09-03

GET /api/v2/geo/admin1 now honours a time window. `days` (or `window=7d`), `date`, `date_start` and `date_end` scope the region counts exactly as they do on GET /api/v2/events, and the window used is reported as `window_days`, `date_start`/`date_end` and a new `applied_filters` receipt. Previously the endpoint read only `country`: `days=7`, `days=90` and `days=abc` all returned the identical 30-day list at HTTP 200, and so did every other parameter sent to it.

Consequently, a parameter this endpoint does not honour now answers 400 UNKNOWN_PARAM naming the accepted set, rather than being dropped behind a 200. This is the change-without-notice case our stability policy names — a filter that silently does not apply.

The pick-list no longer hides regions whose NAME contains the word "and". `Jammu and Kashmir` was absent from the India list while carrying 87 events over the endpoint's own window — more than 24 of the regions it did publish — because a multi-region cleanup rule treated "and" as list punctuation. `Sistan and Baluchestan`, `Andaman and Nicobar Islands`, `Newfoundland and Labrador` and 20-odd more were dropped the same way. Genuine multi-region strings such as `Nevada and Arizona` are still excluded.

The `source` field now reports `none` where neither the settled Events table nor the static catalogue could answer, instead of crediting a catalogue that was never consulted. The published response schema now describes the whole body, including the per-region `values` counts.

2026-09-03

Fixed — several endpoints answered a question they had not actually evaluated. A restricted-party screen for a date outside our observation window returned a clean, warning-free result that was indistinguishable from "we checked and found nothing"; it now returns `screen_status: "inconclusive"` with the reason and the `coverage_window` you can re-run inside. This applies on both sides of the window and on both surfaces that ask it — GET /api/v2/screening/match via `as_of`, and GET /api/v2/lists/entries via `active_on`, which had never been told about coverage at all.

GET /api/v2/filings/{cik} and the entity dossier no longer synthesise a profile for an identifier that does not exist. Both now answer 404 with the resolver to call instead, matching every sibling per-entity endpoint. A malformed CIK still answers 400.

GET /api/v2/geo/admin1 now reads the settled Events table over the published 30-day window and reports the window and per-region event counts. It previously ran an unbounded all-time warehouse scan that could take more than a minute, and on timeout silently served a static region catalogue at HTTP 200 — so two callers asking the same question received different answers, distinguished only by a `source` string.

GET /api/v2/intelligence/coverage now validates its parameters against the contract. Six parameters that were published but never applied (`geo`, `date_start`, `date_end`, `date`, `as_of`, `limit`) now answer 400 rather than being ignored, and the three that worked but were undocumented are published. Responses carry `applied_filters`. GET /api/v2/gleif/entities accepts `country` in ISO-2, ISO-3 or name form like every other endpoint, where it previously matched only ISO-3 and returned zero rows for `DE`. GET /api/v2/epoch/models rejects an unknown `sort` instead of silently coercing it.

GET /api/v2/intelligence/posture?scope=all now returns both scopes; `all` was a published enum value, and the endpoint's own error message offered it, while the response body came back empty.

2026-09-02

Restored — Situations now advance automatically each day from settled Stories. The durable run advances existing occurrences, seeds new ones, reconciles membership, and merges duplicates in dependency order; a failed prerequisite stops later writes instead of publishing a partial chain.

The API and MCP response shapes are unchanged. This restores freshness for the existing Situations product rather than changing its contract.

2026-09-02

Fixed — Data Status is now rebuilt into the public hourly cache before a visitor asks for it. The scheduled refresh had been warming the deployment hostname Vercel uses for cron requests rather than gdeltcloud.com, so the first real visitor after each invalidation could still become the blocking rebuild request.

The event-metric distributions now render into that same server-side snapshot instead of loading from the browser afterward. Served counts, taxonomy, and event metrics continue to read the settled serving tables; the live warehouse remains limited to the processing-clock and coverage-denominator panels it alone can answer.

2026-09-02

Story data now settles incrementally. A settled date used to be rebuilt in full on every run — re-deriving every Story whether or not anything about it had changed — which took about 22 minutes for a busy day against a 13-minute job limit. Days therefore stopped settling partway and could sit hours behind while the job ran on schedule and reported nothing wrong.

Each run now re-derives only the Stories that changed since the previous run and carries the rest forward untouched. A representative re-settle went from 22 minutes to 6 seconds over the same 12,518 Stories. Change detection spans every source that can alter a Story — clusters, articles, entity links, event links, the events themselves, and related-story edges — so a Story that gains a linked event is refreshed even when the cluster itself did not move.

Full rebuilds still run once a date closes and remain the authority; the incremental pass only affects how quickly recent data becomes available. You may notice Stories and their linked-event counts for the current and previous day updating sooner.

2026-09-01

Faster — a Monitor now answers from the same endpoints you call. Every Monitor lane runs `GET /api/v2/events` or `GET /api/v2/stories` for its rows and `/events/summary` or `/stories/summary` for its match count, instead of a second implementation of the same query. That means Monitors read the settled serving tables, are response-cached, resolve entity ids through the same arbiter, and inherit every correctness fix that lands on those endpoints. Whatever a Monitor reports, you can now reproduce by hand from the same parameters.

Fixed — a Monitor that filtered by BOTH a CAMEO+ domain and a conflict category could return zero Stories. The two filters were sent as separate parameters and combined with AND, and an event belongs to one family or the other, so the combination was unsatisfiable. They are now one comma-separated `category` filter, which is an OR — a Mexico Monitor watching CRIME plus Protests/Riots/Violence against civilians was reporting `story_count: 0` while its event lanes returned 21 matches.

Fixed — a Monitor with two or more CAMEO+ domains no longer fails. Event taxonomy is sent as `category`, which accepts a comma-separated list of ACLED event types and CAMEO+ domains together; three of our published workflow templates carry two domains.

Fixed — `story_count` is a total again, not a ceiling. It was counted through a candidate query capped at 1,000 rows, so a busy Monitor reported exactly 1,000 with `count_truncated: false` against a true figure several times higher. The count is now an aggregation over the window and has no cap. A `search=` Monitor still reports its candidate limit honestly, which is a real bound rather than an artifact.

Fixed — `GET /api/v2/events/summary` and `GET /api/v2/stories/summary` now accept `near` / `lat` / `lon` / `radius_km`. The list endpoints have supported point proximity for some time and the summaries answered 400 UNKNOWN_PARAM, so you could retrieve the events near an asset and had no way to count them.

Changed — `story_category` on `GET /api/v2/stories` and `/stories/summary` accepts a comma-separated list for OR. A single value behaves exactly as before.

Worth knowing — because Monitors now read the settled tables, a rolling 24-hour window reflects what those endpoints return in the same moment, which on the newest hours can be behind the raw ingest side while the snapshot catches up. Older windows are unaffected: the same query over a two-day-old window returns an identical set from either source.

2026-09-01

Faster — entity name search is now lexical end to end. `GET /api/v2/search` and the `search=` parameter on `GET /api/v2/entities` no longer run a semantic (embedding) pass, which removes an OpenAI round trip and a multi-gigabyte similarity scan from every request. `/api/v2/entities?search=` was the slowest endpoint we measure; the semantic reference query alone read 1.92 GiB and the media one scanned a column that was empty, so it could never return a row.

What changes in your results: on a query that already resolved, nothing — semantic hits always ranked below every lexical tier, so they were not what you were being served. On a query that resolved to little or nothing, a small number of unrelated entities will stop appearing. Measured across 25 representative queries the semantic pass contributed 5 results the lexical tiers had not already found, on 3 queries, and every one was wrong — including on the transliterated non-Latin names the pass existed for, which the lexical tiers resolve correctly on their own.

Changed — a name search that lands on an entity whose own alias set names several different organizations is now reported as `match_type: "ambiguous_alias"` instead of `"exact_alias"`, with a `match_reason` saying why, and it no longer outranks a real match. Searching `Pemex` returned a Brazilian military police force as a confident exact match, because that record had accumulated aliases for Pemex, two police bodies, a Romanian political party and two public ministries. The underlying records are being repaired separately; this stops search presenting them as certainties in the meantime.

Changed — a fuzzy or typo-tier match must now account for every meaningful word you typed, not just its closest one. `KLA Corporation` was returning CPC, MTR, FPT and AES Corporation, and `Renesas Electronics` was returning 3-K Electronics Limited, on the strength of the shared word alone. Exact, token-set, acronym and prefix matches are unaffected, and a genuine misspelling still matches.

2026-09-01

Changed — a new Monitor now watches ONE lane: `criteria.data` is `events` for coded incidents or `stories` for coverage clusters, and it defaults to `events`. The builder offers exactly those two. Want both? Create two Monitors — they run and fail independently, and you can give each one its own cadence and recipients.

Unchanged for anyone already running — `events_and_stories` is DEPRECATED, not removed. It is still accepted by `POST /api/v2/monitors`, `PATCH /api/v2/monitors/{id}` and `POST /api/v2/monitors/preview`, and every saved Monitor carrying it keeps executing both lanes exactly as before. Nothing needs migrating today, no Monitor was rewritten, and the value will not be withdrawn inside the published 30-day notice period. It no longer appears in the builder for new Monitors, in the shipped workflow examples, or as an example in the OpenAPI spec — but it is still in the spec enum, so a generated client can continue to read and send it.

Why: both lanes in one Monitor share a fate. They contend for the same warehouse, so a slow Story lane returns 503 for the whole Monitor including an events half that already answered in about a second. Measured in production, mean execution time was 35.1 s for `events_and_stories` against 25.5 s for `events` and 26.3 s for `stories`, and in a 40-request Preview sweep every reproducible 503 was a both-lanes specification.

It also fixes a count. `sample_count` is `event_count + story_count`, so one incident that appears as a Story AND as its coded Event was counted twice — a single-lane Monitor reports the number of things that actually happened.

2026-09-01

Changed — `?country=` on `/api/v2/stories` now returns the Stories that are ABOUT a country, including those with no coded Event. Expect materially more results for the same request. Walking every page of a single day (2026-08-31) with `limit=100`: `country=MEX` returned 131 Stories where it previously returned 6, and `country=USA` returned 1,355 where it previously returned 197 — seven to twenty times more, depending on how much of a country's coverage was already event-coded. If you are reconciling against yesterday's numbers, this is why. The same widening applies to `region=` and `continent=`, which resolve to country sets, and to `group_by=country`/`region`/`continent` on `/api/v2/stories/summary`.

Why the old behaviour was wrong: a Story has no coordinates of its own, so `?country=` was answered entirely through the Story's linked Events. Of 325,564 Stories served over a 30-day window, 259,136 — 79.6% — carry no coded Event, and every one of them was unreachable by any country filter in any spelling. `?country=` silently also meant `has_events=true`, which is not a documented part of its meaning and is not what it says. Stories now carry their own country attribution, normalised through the same resolver that validates your filter, so `Colombia`, `CO` and `COL` all land on the same ISO3 and an unrecognised code still matches nothing.

Unchanged — `country_match=location` keeps the narrower, event-located meaning: it asks where a coded Event happened, and a Story's topical attribution is not a location witness. Send `country_match=location` to reproduce the previous result set. A country combined with any other event-scoped filter (`category`, `subcategory`, `domain`, `admin1`, `bbox`, `civilian_targeting`) also keeps the previous meaning, because those ask about the Story's Events and an eventless Story cannot answer them — matching the country while silently ignoring the rest would be worse than returning less. Windows before July 2026 predate the attribution and are unaffected.

Also — Story reads now select candidates from the settled serving tables rather than the live warehouse, so `meta.row_source: settled` describes the whole query rather than half of it. Requests whose window has not finished settling still fall back to the live path and report `row_source: live`.

2026-09-01

New — `entity=` on `/api/v2/events` and `/api/v2/stories` now accepts up to 25 comma-separated handles and returns their UNION: a row is included if ANY of them matches, never only the rows matching all of them. A watchlist is one request instead of twenty-five. Previously a comma list was refused with `400 MULTIPLE_ENTITY_HANDLES`, even though a Monitor subject already groups up to 25 entities — so the product offered a question the API could not express. The same applies to `/api/v2/events/summary` and `/api/v2/stories/summary`, so retrieve-then-summarize still agrees across the two calls.

Every handle resolves through the same shared entity arbiter a single handle uses, so an id, a `wiki:` id or a plain name means the same entity alone or twenty-fifth in a list. `applied_filters` echoes `entity_handles` with the full list, and `entity_handles_unresolved` names any handle that reached no coverage — a handle that resolves to nothing contributes no rows and never widens the result. More than 25 handles is refused with a 400 naming the limit rather than silently answering for the first 25. A single handle is unchanged in every respect.

`co_occurring_with` on `/api/v2/entities` still takes exactly one subject: "who appears alongside A or B" is a different question whose answer must exclude the subject, and a two-subject exclusion would change what every returned row means.

2026-09-01

Fixed — a Monitor's Story match count stopped at 1,000 and reported itself as complete. The count is drawn from a candidate pool that caps at 1,000 regardless of the limit requested, so a busy window understated Story volume — measured against a 25-country Monitor, roughly fourfold — while `count_truncated` said `false`. The count now reports `count_truncated: true` when it reaches that ceiling, so a number that is a floor is no longer published as a total. Event counts were never affected: that lane runs an uncapped count.

Improved — Event and Story reads no longer carry the 1536-dimension embedding vector through queries that never use it. It is loaded only when a request actually asks for semantic search. Measured against production on an entity-scoped read, one lane went from 49.0s to 14.3s and another from failing outright — three stacked statement timeouts — to 17.9s, returning the same rows. Results are unchanged; only what the query reads from disk is.

Fixed — Monitor Preview ran every lane query twice, the second time only to decide how many rows from each lane to display. It now rebalances the sample from the rows it already fetched, and resolves a facility target once rather than twice.

Fixed — a Monitor query that exceeds its time limit now fails once instead of being retried three times, which turned a 30-second timeout into 90 seconds of repeated identical work.

Fixed — the Monitor Preview delivery transcript no longer shows an empty match list beside a non-zero match count. The signed request body is shown as the exact bytes the signature covers, and the real request and response are one click away in the API view. An absent match count now renders as “—” rather than “0”.

2026-08-31

Fixed — Facilities now recover owner relationships from Global Energy Monitor’s normalized ownership registry, resolve them through the canonical entity spine, and use the canonical entity display name. Owner links therefore connect to the same entity and portfolio returned by the other API datasets.

Fixed — placeholder and person records no longer become navigable organization links, incomplete evidence remains honestly name-only, duplicate owner tuples are removed, and existing facility ids remain stable when a source normalizes mutable fields such as missing-value sentinels.

2026-08-31

Fixed — World Port Index fields no longer turn missing draft measurements into 0 or collapse unknown terminal flags into false; those states now return null with their source identified. Port Pulse now matches ports to the AIS bounding boxes the sampler actually covers, and its structured coverage object is documented as served.

Fixed — Share of Voice treats source_set=all as the complete served Story corpus instead of the literal domain “all”, Atlas GPR errors name only the parameters that conflict in the public vocabulary, and the Facilities context specification now publishes its real 30-day default.

2026-08-31

Fixed — a Monitor’s separately labelled 30-day historical Preview now reads the full requested date range instead of retaining the default two-day partition bound. Country criteria on entity, topic, facility, place, and category Monitors now use the same location-or-actor-origin definition as the Events and Stories APIs, while geography subjects remain explicitly location-only; replay requests carry the exact definition used.

Fixed — Facilities owner filters now include every entity alias that resolves to the canonical owner, and returned owner ids and portfolio links use that canonical id. Following an owner link from a facility therefore returns the same complete portfolio whether the underlying registry row predates or follows an entity merge.

2026-08-31

Changed — every Monitor Builder Preview is now a complete webhook demonstration. The Builder runs the real one-query-unit Preview, sends a canonical signed `monitor.test` event through the same transport used by saved Monitors to a two-minute first-party receiver, verifies it, and shows the actual request and response transcript. Preview creates no saved Monitor or delivery record; saving an external webhook remains plan-gated.

Changed — the AI prefill has been replaced by three editable starters for TSMC supply-chain coverage, Mexico operations security, and global fatal conflict events. Each starter is webhook-first and produces both the real Preview call and an honest production creation example with email disabled.

2026-08-31

Fixed — Facilities now resolve canonical and slugged facility ids consistently and expand an empty short owner-coverage window to an explicitly labelled 30-day example. Radius event queries retain the settled bounding-box acceleration while applying exact great-circle distance.

Fixed — Share of Voice arrays remain aligned with their entity ids, country scope now matches the documented location-or-actor-origin meaning, Tone accepts canonical entity ids, and all public analytics queries enforce the shared 30-day maximum. Atlas rejects incompatible corpus or posture-window combinations with stable client errors. Warehouse details are no longer exposed in these user-facing error responses.

2026-08-31

Changed — on a Situation, the event taxonomy, the two country facets and the coder’s metric spreads now read beside the map, under the title and summary, instead of below it. The taxonomy and the country facets came up out of the composition band and the metric spreads came back out of the “Everything in this occurrence” disclosure; each renders in exactly one place on the page, and each states whether it is measured over the whole occurrence or over the day the dragger is on. Drag the day handle and all three re-answer with the lanes below them — on 2026-08-29 of one four-day occurrence, the taxonomy, both facets, the spreads and the band all report 9 coded events against the same 9.

Fixed — the day timeline’s labels no longer sit in the right-hand bezel. The axis runs to the true edge of the map, which is deliberate, but the final date, the per-day tally, the scrubbed reading and the drag handle were pinned to that same edge: measured at 1440×900 and 1920×1080, all four ended exactly at the viewport width and the handle overhung it by 11px. The text and the handle now clamp a gutter inside the axis; the axis itself has not moved.

Changed — Expand situation and API view moved above the title, and the column now reserves the account/quota strip’s band so they stay clickable at every width. The strip is right-anchored and sized to the account: on a 768px-wide window it reached across and painted over the Expand button, which looks fine in a screenshot and is dead to the mouse.

2026-08-31

Fixed — an edge in `GET /api/v2/situations/{id}` now points one way, and the same way on every request. `story_links` stores both directions of every adjudicated pair; the serve layer keeps one undirected edge, and which of the two rows survived was decided by result order — so `from`, `to` and `relation` moved between requests. Measured on one production occurrence, two fetches minutes apart returned `precursor 79 / continuation 83` and `precursor 31 / continuation 131` over an identical set of 229 pairs: 49 edges (21.4%) flipped. Every edge was correct on both occasions and the mix was not reproducible. Edges are now oriented earliest-first — with the story id breaking a same-day tie — the array is totally ordered, and eight consecutive fetches returned a byte-identical `edges`.

Changed — `edges[].relation` no longer returns `precursor`. On an edge oriented earliest-first, “A precedes B” and “B continues A” are the same fact read from opposite ends, so publishing both was what made the direction unstable; the published enum is now `same_day`, `continuation` and `duplicate`. A Story’s precursors are the `from` ends of the edges whose `to` is that Story. `stories[].relation` is unchanged and still carries all three directions — it is measured against the situation’s anchor, which is a fixed point. `duplicate` edges are untouched: they are a verdict about identity, never re-derived from dates and never dropped.

Changed — on the Situation graph, the indigo/rose pair now reads against the occurrence’s peak day rather than against each edge’s own ends: indigo before it, rose after it, and an edge that spans the peak day is drawn in both instead of being filed under one. The old reading was a property of result order rather than of the situation; this one is stable, and where it comes out in a single colour that is a fact about the occurrence.

2026-08-30

Fixed — Top Event and Top Story cards in Atlas now open their public detail page in a new tab, preserving the Atlas view and time-machine office for comparison.

2026-08-30

Fixed — the editorial reviewer that decides whether a coded event is publishable was suppressing a large share of otherwise-sound events because of how it read their occurrence date. On 2026-08-21 the rule changed from "the incident happened on one of the processing dates" to "the incident has an evidenced occurrence date", so that an event newly reported today but which happened earlier could still publish. That widening is correct and is unchanged. What was missing is that the rule never said which kinds of date evidence COUNT, so the reviewer treated routine same-day news reporting — where the date is the day of publication, and the article states no date because none is needed — as unevidenced, and rejected it.

The reviewer now reads the four documented values of `event_date_basis` explicitly, and same-day publication-day inference is stated to be a valid anchor. Rejection for date reasons is reserved for a date the card's own evidence contradicts, a historical event an article merely mentions in passing, or a tally spanning several days. Nothing that the 2026-08-21 change added has been removed: a newly reported earlier occurrence still publishes, and the Story-versus-Event consistency check is unchanged.

What you may notice: more events per day, concentrated in ordinary same-day reporting, with no change to how events dated by an explicit or relative date in the text are handled. Measured on 150 production event cards, judged twice under each policy: the publishable rate moved 77.3% to 89.7%, date-scope rejections of same-day reporting fell from 29 to 1, and rejections of explicitly-dated and relative-dated events did not move at all. An independent adjudication of the recovered events found 90.6% of them sound (95% CI 75.8%-96.8%) and identified no date defects among them. Events already published are unaffected; this changes what gets published from here.

2026-08-30

Fixed — `GET /api/v2/situations/{id}` was omitting the LARGEST member of every curated Situation from `stories` while counting it in every total beside it. On one production occurrence that was a 1,297-article Story, 27% of its coverage, present in `totals`, in `by_date` and in the incident and entity roll-ups, and absent from the one array a caller reads. `pagination.total` now equals `totals.story_count` on every response, and a test pins that alongside `sum(by_date.story_count) = totals.story_count`.

Changed — `edges` is now returned only when you send `include=edges`. It was roughly half the payload (measured: 46 KB without it against 94 KB with it) and every caller was paying for the graph whether or not they drew it. `totals.edge_count` is returned either way, so the decision to make the second call does not need the first one to carry the answer.

Fixed — `date_start`, `date_end` and `max_nodes` did nothing on a curated Situation: a 90-day window returned 200 and a three-day one returned the whole occurrence. They now filter the membership before the payload is assembled, `coverage` is re-derived from the members that survived, and the published 30-day ceiling refuses a wider span on this path as it always did on the other. `depth` cannot apply to a set that was adjudicated rather than walked, so it is reported under `applied_filters.ignored` instead of being echoed back as honoured.

Added — `caps` reports every bounded array: the member ceiling, a new ceiling on `incidents` (that query carried none at all), and the 40-entity cast limit, each with whether it bit. The entity figure is the count the cap applied to, before merged ids are folded onto their survivor — so 40 rolled-up ids legitimately render as 39 rows, and the two numbers can be reconciled rather than merely compared. `totals.distinct_incident_count` sits beside `story_count` for the same reason: a curated Situation admits Stories a judge called a re-telling of another, and nothing said how many of the count they were.

2026-08-30

Fixed — a Situation’s stored story and event counts now mean the same thing the Situation page and `GET /api/v2/situations/{id}` report. The counts on the Situations list and in the “Part of a N-story situation” link on Story pages could disagree with the page they lead to — one situation advertised 32 stories and 16 events against 31 and 19 served.

Two causes. The stored event count was measured over a different span from the served one, and both now come from a single query definition. And the counts are a cache of what the settled tables answer, which changes as a day is re-settled without any membership changing — so they are now refreshed on every nightly pass rather than only when a Story is added.

2026-08-29

Changed — Situation pages are now a signed-in surface and have moved behind the app shell, with their own entry in the sidebar beneath Atlas. They were briefly public; an adjudicated claim about what belongs to one occurrence is the product rather than a teaser for it. The public allowlist entry and the sitemap block went with them.

Added — `GET /api/v2/situations/{id}` now returns `entities` and `composition`. `entities` is the cast our OWN resolver bound to the member Stories, with `story_count` scoped to the situation — how many of its Stories carry that entity, not the entity’s global coverage — and `entity_type` taken from the entity register rather than from the mention rows, which type people as locations. `composition` counts the occurrence by category, event type and country, derived from the incidents already in the payload so the two can never disagree.

Added — a Situation can now be built or extended from the page itself, on any Story and on the Situation view. It runs a real adjudication per candidate and costs 5 QU, which the button states before you press it. A Story already inside a Situation extends THAT Situation rather than starting a rival.

The page is rebuilt around the map: incidents plotted and auto-zoomed to where the occurrence happened, the day-by-day cluster graph beneath it, and the key Events, key Stories and cast beside it. The full member list is gone — the graph was already showing it.

2026-08-29

New — `GET /api/v2/entities?co_occurring_with=<handle>` returns the entities that appear ALONGSIDE one entity: the entities linked to the same Stories, over the same window. It is a parameter on the entity list rather than a new endpoint, so it composes with every filter already there — `co_occurring_with=<handle>&country=IRN&languages=ar&type=organization` is one call. The handle is a spine id (`e_…`), a news id (`wiki:…`) or a name, resolved through the same arbiter as `entity=` on /events and /stories, so one handle means the same entity everywhere.

Three semantics worth knowing. The subject is never returned in its own results. Co-occurrence is SHARED COVERAGE — appearing in the same stories — and is not a claim that the two entities interacted. Each row's metrics are scoped to the shared stories and the response says so with `metrics_scope: "filter_scoped"`, so a neighbour's `story_count` is stories shared with the subject, not its window total. A handle that resolves to nothing returns an empty list with a `linkage` reason in `applied_filters` — never the global top entities.

Changed — `/api/v2/entities` now answers 400 `UNSUPPORTED_FILTER` to `entity` / `entity_id` / `entities`, naming `co_occurring_with` and `GET /api/v2/entities/{entity_id}` as the alternatives. Those spellings were never parameters on this endpoint and already answered 400 `UNKNOWN_PARAM`; the refusal now says what to send instead.

Deprecated — `source_mix` on `GET /api/v2/entities/{entity_id}`, scheduled for removal on or after 2026-09-28. It cannot be served correctly: per-article domain exists only in the warehouse, and the same query shape measured ~9.8% of all production ClickHouse memory on 2026-08-02. It is unchanged and still populated until that date; the field carries `deprecated: true` in the OpenAPI spec and the date is published at docs.gdeltcloud.com/reference/stability. For per-outlet coverage of a Story, read `source_count` and the domain list on `GET /api/v2/stories/{id}`. The Source Coverage panel on the public entity page is gone now.

2026-08-29

Events now serve `event_description` — the coder's own free-text wording for that specific event (e.g. "Landslide"), which is usually more specific than `subcategory_label`, the name of the CODE it was filed under ("Geophysical Hazard"). It is CAMEO+ only and NULL for the conflict family, whose `subcategory` already carries its ACLED sub-event type. It is free text: not stable, not a filter value, and not safe to group by — group on `subcategory`.

`subcategory_label` no longer carries the CAMEO codebook's embedded Goldstein score. 42 taxonomy labels read like "Make a visit (+1.9)"; a field naming a code should not have a number baked into it, and the value was neither filterable nor parseable. The score is unchanged and still served as its own numeric in `metrics.goldstein_scale`. If you parsed that suffix out of the label, read the metric instead.

2026-08-29

Added — Situations are now records with their own pages. A Situation is one real-world occurrence together with its chronological causal thread: what led to it, the occurrence itself, and what followed. Each Story in one carries the route it joined by — antecedent, occurrence or consequence — decided against the occurrence as a whole rather than against the Story it began with.

Every Story page that belongs to one now links to it, and `/api/v2/situations/{id}` accepts either a situation id or any member Story id and returns the same occurrence. A Situation that merges into another resolves forward to the survivor rather than breaking the link.

Two figures are reported side by side rather than as one: where an occurrence began (its earliest member with material coverage) and where it peaked (its largest). They are usually different Stories, and both are recomputed as the occurrence develops.

2026-08-29

Added — `GET /api/v2/situations/{story_id}` returns one real-world occurrence: the Stories that belong to it, a per-day rollup, the Events collapsed to one row per canonical incident, and — on `include=edges` — the adjudicated links between them as an explicit edge list. The Story id in the path is the address, not a group id — ask any member and you get the same occurrence.

Fatalities are reported as a maximum beside a raw sum, and the incident count ships with its adjudication split, because most Events have never been compared to another. Members and Events resolve through the same settled tables /api/v2/stories and /api/v2/events read, so a situation can never name a record those endpoints will not return.

`depth` walks further out. A Story at hop 1 was compared with the anchor directly; at hop 2 or more it was reached along a path of individually adjudicated links, and `via_story_id` names the neighbour it came through. No link in the corpus spans more than two days, so reaching across a week is depth rather than distance.

Changed — adjudicated Story links and the verdicts behind them are no longer deleted after 90 and 30 days. A situation is exactly the thing a retention cliff truncates.

2026-08-28

Fixed — the docs said the plugin ships five skills on four pages, including the quickstart. It ships eight, and the count is now checked against the skills that exist rather than typed.

Fixed — the quickstart claimed Event and Story lists default to a rolling 7-day window, contradicting the parameter reference. Omitting the window bounds a request to the last two days, and the quickstart now says so.

Fixed — the Plugins card on the homepage overlapped the headline below roughly 1,700px of viewport width. Its width is now derived from the space the headline leaves, so the two cannot collide at any size.

2026-08-28

Builder now runs 3 daily Monitors, up from 2. Existing Builder accounts get the extra capacity automatically — no action needed, and nothing else about the plan changes.

Scheduled Monitor runs still cost no Query Units on any plan: Monitors are meant to replace the Query Units that polling for the same answer used to spend.

2026-08-28

Added — the Usage page now shows a plan-limits ledger: what your plan grants, any adjustment held on your account, and the limit actually in force, per entitlement. Grandfathered allowances are labelled as such. The Query Unit tile previously headed “Base” showed the adjusted figure, not the plan’s, and is now “Your limit”.

Fixed — usage-limit notices correctly measure accounts whose Query Unit allowance was adjusted or grandfathered, instead of skipping them. The at-limit notice now names the status a quota wall actually returns (429 QUOTA_EXCEEDED) and describes automatic top-ups without a per-period cap that no plan carries.

Fixed — trial and subscription dates render in one explicit format everywhere. An evaluation end date previously rendered in the reader’s locale, so “04/09/2026” meant two different days to two different readers.

2026-08-28

Fixed — incident reconciliation now proposes exact source-title, exact event-title and same-region/date-window candidates before independent adjudication, recovering repeated attacks and decisions that differed in actor spelling, place detail or report date.

Improved — Atlas GPR counts an adjudicated incident survivor once instead of counting every duplicate Event row. Event occurrence-date evidence now reaches the API, while `observed_at` records source-stream observation time rather than borrowing the model coding timestamp.

Changed — Event duplicate handling now has one versioned identity policy and one post-publication incident authority. Accepted membership is monotonic, stale missing-survivor pointers self-repair, and positive and negative pair verdicts retain their evidence and rationale. Every public Event surface now returns one canonical incident identity; older member ids remain working aliases, and raw duplicate rows are retained only as internal provenance rather than exposed through a `collapse_duplicates` switch.

Fixed — hourly serving publication now reserves one run for the active date and one for late-arriving backlog, so today stays current while older dates cannot be starved indefinitely. Incident reconciliation follows the same lifecycle: today is checked hourly and a separate weighted pass revisits the prior seven event dates, so an Event coded late is still compared on the day it actually occurred. Event observation lineage is restored from the persisted Event or its canonical Story clock; a coding timestamp is never substituted for an unknown observation time.

2026-08-28

Launched — Monitors now has a public workflow showcase for the standing questions supply-chain, security, country-risk, communications and product teams ask repeatedly, with real AI Builder, Preview and saved-run evidence views.

Improved — the public site now explains the cleaner dates, provenance, evidence, duplicate handling and entity linking underneath Events and Stories, including explicit coverage and uncertainty when the data cannot support a complete answer.

2026-08-27

Fixed — Entity Tone now applies category filters consistently to language coverage, withholds tone, risk and channel labels when evidence was not scored, keeps canonical entity identity stable across rows, and rewrites merged story references to their surviving ids.

Improved — ambiguous exact aliases are independently adjudicated in article context before binding, and material company results, guidance, exceptional issuer moves and C-suite succession are now eligible for Story ingestion. The API schema now documents Tone confidence fields and Story detail image and entity-tone expansions; Pricing names Tone and Share of Voice directly.

2026-08-27

Improved — Monitor AI drafting now explicitly decomposes intent, chooses among Entity, Geography, Facility, map-area, Category and Topic subjects, and prefers exact actor, location and taxonomy filters before semantic search.

Improved — the Monitor builder now resolves facilities by name, supports point-and-radius selection on a map, provides closed timezone and local-hour selectors, explains the AI draft plan, and uses a higher-contrast guided four-step layout.

2026-08-27

Improved — the Monitors page now shows running capacity and total saved Monitors beside the page actions, using the organization's effective plan allowance.

Changed — `max_monitors` now limits running schedules only. You can save additional Monitors after every slot is occupied; they are created paused and can be resumed when a slot opens. `GET /api/v2/monitors` now reports active, total and available-slot counts plus separate create and activate capabilities.

2026-08-27

Improved — Pricing and the signed-in Subscription page now use the same plan order and comparison structure, with Query Units, Monitor capacity, included Briefs and exact seat counts visible on every plan card.

Simplified — the marketing header and footer no longer include the generic Product dropdown or Product link, leaving the primary demos, Pricing, Docs and About as the public navigation paths.

2026-08-27

Improved — the Monitor AI drafter now decomposes requests into actor, action or mechanism, target, directionality, required concepts, exclusions and location-versus-actor meaning before filling the public Monitor contract. Broad taxonomy categories are treated as optional refinements rather than substitutes for a relational question.

Added — Event Monitors can filter CAMEO+ source and target actor countries independently using closed ISO-3 country pickers. Actor identity stays separate from Event location, and the filters use the existing indexed Events serving path without a warehouse migration.

2026-08-27

Improved — Monitors now sits directly beneath Atlas in the signed-in navigation with a radar icon that better communicates an active watch. Briefs is no longer labelled Beta.

Improved — the signed-in Subscription page now presents Academic & Research as a full comparison card matching the public pricing ladder, with its live Query Unit, Monitor, Brief, module and bulk-download entitlements shown before the access request.

2026-08-27

Improved — the Monitor builder now uses searchable, multi-select enum pickers for countries and taxonomy values. Country, region and continent are mutually exclusive scopes; state/province appears only after choosing exactly one country; and event subcategories appear only after their parent categories are selected.

CAMEO+ and Conflict remain distinct API vocabularies but are presented together as one Event taxonomy section with user-facing labels. Story categories are also a closed, friendly-labelled enum, while duplicate collapsing remains an internal default instead of a customer-facing setting.

2026-08-27

Fixed — entity search now treats legal-form variants as the same relevance class, so recent resolved coverage can put SIEMENS PLC above an exact but zero-coverage Siemens identity without allowing an unrelated alias to win. Native non-Latin name input now returns 400 UNSUPPORTED_SEARCH_SCRIPT with a Romanization hint instead of plausible unrelated candidates; Latin text and Latin-script diacritics are unchanged.

Fixed — Monitors accept a resolver-issued `wiki:` or `llm:` subject when it has resolved news coverage even if it has no active display-registry row. Monitor run pages now present readable Event and Story evidence cards with source links; the full structured record remains available in a collapsed disclosure.

Fixed — Atlas GPR keeps the current UTC day visible but marks it `insufficient_data: true` with reason `current_day_partial`, withholding the index and band until the live daily bucket closes. The homepage reduced-motion preference no longer produces different server and first-client markup during hydration.

Fixed — resolver-issued `wiki:` entity ids now round-trip through entity detail even when identity is established by resolved coverage rather than the display registry, Facilities treats `owner=e_…` as the documented exact-id alias, and an empty Monitor Preview can show a separately labelled 30-day historical example without altering the real rolling-window evaluation.

2026-08-27

Fixed — generic entity-name resolution now has one candidate order across GET /api/v2/search, GET /api/v2/entities?search=, event and story entity filters, Tone, Share of Voice, the Monitor picker and the API Arena. Endpoint-specific coverage can filter or annotate the winning entity, but it no longer silently promotes a different namesake.

Automatic binding remains deliberately stricter than candidate search: Search may show weak fuzzy or semantic suggestions, while a data endpoint returns an explicit unresolved error instead of serving another entity's rows. Resolve a name once through /api/v2/search and reuse its id for an unambiguous chain.

2026-08-27

Added — saved Monitors now have Run now for immediate testing. A manual run costs 1 QU and is retained for seven days even when it finds zero matches, while deliberately sending no notification, advancing no match state, and changing no schedule.

Added — every retained Monitor match can be downloaded as UTF-8 CSV from `GET /api/v2/monitors/{id}/runs/{runId}/matches.csv`, with both the frozen as-triggered assertion and the current hydrated record. The export reports exact-versus-retained counts so a capped snapshot cannot look complete.

Fixed — unknown article dates represented by the warehouse epoch sentinel now appear as `null` instead of the misleading date `1970-01-01`.

2026-08-26

Improved — `POST /api/v2/monitors/{id}/test-delivery` now really tests EMAIL, not just webhooks. Email is the default delivery for a Monitor and it had no test at all: the endpoint reported `reason: "email_only"` and left you to wait a full cadence — up to 24 hours on a daily Monitor — to find out whether mail reaches you. A configured email channel now receives a real test message, at the same address a triggered run would use and from the same sender, so deliverability is answered in seconds.

The reply describes every channel under `channels`, and the top-level `delivered`/`reason`/`error` now carry the email's outcome for an email-only Monitor instead of a `not_configured` that was only ever true of the webhook. Webhook behaviour and its top-level fields are unchanged.

A suppressed delivery address is reported rather than mailed — that is the single most likely reason scheduled Monitor mail is not arriving, and it was previously invisible from your side. Email tests are rate-limited per organization; a refusal answers `channels.email.retry_after_seconds`.

It is a delivery test and deliberately not a "run now": nothing is evaluated, no matches are marked as seen, and nothing appears in the Monitor's run history. In the app, the Delivery panel's test button is no longer webhook-only and now reports each channel's result in place.

2026-08-26

Changed — the public Alerts API is retired. Monitors replaced it, and the eight `/api/alerts*` paths now answer `410 Gone` naming their `/api/v2/monitors` successor in the response body, in `details.replacement` and in an RFC 8594 `Link` header. 410 rather than 404 on purpose: "intentionally gone" is something caches and retry policies act on, while a 404 is indistinguishable from an outage and invites a client to retry forever.

The successors are one-for-one. `GET`/`POST /api/alerts` becomes `/api/v2/monitors`, `/api/alerts/preview` becomes `/api/v2/monitors/preview` — the same execution, reached through the public `subject`/`criteria`/`trigger` contract instead of a raw `spec_json` — `/api/alerts/{id}` keeps its id at `/api/v2/monitors/{id}`, and the logs and results paths become `/api/v2/monitors/{id}/runs`. Replaying a stored window no longer costs a re-execution: a run detail publishes `replay_requests`, the exact /api/v2 calls and window bounds that reproduce it.

Bookmarked `/alerts` pages still redirect to `/monitors`, and Monitors themselves are unchanged — scheduling, execution and delivery run on the same engine they always have.

Fixed in the same pass — the published OpenAPI advertised a Monitor preview response shape the service refuses. `MonitorPreviewExecution.normalized_spec` carried an `alert_kind: "spike"` variant with `threshold_multiplier`, plus two more variants no public request can produce, because an internal schema was flowing into a published response type. The spec now publishes only what the public trigger can produce, derived from the trigger contract rather than listed by hand.

2026-08-26

Improved — the Monitor entity picker now shows each candidate's 30-day coverage, the number the API has always returned as `coverage_30d` and the docs tell you to check before choosing an ID. Searching "Siemens" returned four candidates with an identical match score of 7.00, and the only one the picker put first had zero resolved stories — a Monitor on it would run on schedule and never match. The number was on the response the whole time; the picker was not rendering it.

A candidate with no coverage is now called out rather than merely numbered, selected IDs keep the figure on their chip after the result list closes, and a Monitor whose subject includes a zero-coverage ID warns before you save it. Candidate ORDER is unchanged: match tier deliberately outranks coverage, so a better-covered but worse match never takes the top slot, and coverage is shown so you can break the tie yourself.

Fixed — "Generate draft" now tells you what went wrong. Every failure — no provider key, a provider error, a timeout, or output that did not satisfy the Monitor contract — previously returned one sentence, "temporarily unavailable", with nothing in the server log. Responses now carry a `reason` and a `retryable` flag, a retryable failure carries `Retry-After`, and the message stays on screen next to the prompt instead of vanishing with a toast.

Fixed — the draft request is now bounded in the browser. It had no timeout at all, so a slow response left the button spinning indefinitely with no elapsed time and no way to cancel; it now shows how long it has been waiting and gives up with a clear message. Separately, a draft that had already been generated could be thrown away by a failure to write an internal usage row; that no longer happens.

2026-08-26

Fixed — a semantic search combined with an entity no longer escapes the entity. Asking a Story question with both an entity and a `search` term ranked candidates across the whole corpus and only then applied the entity, because the semantic candidate query was the one place that quietly ignored the entity constraint. The Event half was never affected.

It surfaced two different ways, which is why it took a while to name. An entity Monitor with a search term returned the global news corpus — a Siemens Monitor answered with Ukrainian drone strikes, Volkswagen job cuts and a sesame-oil recall — while reporting the entity as an applied filter. On GET /api/v2/stories, which intersected the results afterwards, the same defect returned an empty list instead: `entity=…` alone returned rows and `entity=…&search=…` returned none, for every entity and every term.

Both now scope in the query itself, so the search ranks within the entity rather than across everything and then filtering. In the verification case the entity has 16 Stories in the window, and every search over it now returns those 16 re-ranked by relevance rather than 0. An entity with no coverage still returns empty, never the corpus.

If you combined `search` with `entity` on Stories, on /api/v2/stories or in a Monitor, re-run it: previous results were either unrelated or missing, never partial.

2026-08-26

Fixed — two pages sold a Monitor trigger the API has never accepted. The pricing page listed "new-match and volume-spike triggers", and the homepage said live Monitors "surface emerging spikes". A Monitor has exactly one trigger: it fires on new matches. Sending anything else to POST /api/v2/monitors answers 400 VOLUME_SPIKE_NOT_SUPPORTED, and always has — so the first thing anyone built on that sentence failed.

Nothing about Monitors changed; only the description of them did. Every other surface a developer meets was already correct and stays as it is — the schema, the published OpenAPI, the error reference and all five Monitor workflow examples say new matches and nothing else. Volume-spike triggering remains deliberately deferred rather than shipped ahead of independent validation, and the error reference continues to name it so a caller who tries gets a straight answer instead of a silent empty result.

The homepage tile also linked that promise to Early Signals, which is a recency-ordered public watchlist and computes no spike of any kind. It now describes what it actually shows: new matching events as they are detected and geocoded.

A guard now derives the accepted trigger set from the Monitor contract itself and fails our test suite if any customer-facing page advertises a trigger the API refuses — or, when a second trigger genuinely ships, if the pricing page fails to mention it.

2026-08-26

Fixed — changing plan now brings your Monitors with it. The Monitor limit was checked only when you created one, so an organization that downgraded kept every Monitor it already had enabled and running: ten Monitors on a plan that sells two carried on checking, notifying and spending query units. Every plan change now reconciles the count — the Stripe webhook, a self-serve plan change, a cancellation, an admin grant or its removal, an entitlement override, and the end of an Explore evaluation.

Over the limit, the excess is DEACTIVATED and never deleted. The oldest Monitors keep running and the newest are paused, on the same rule creation already implies: at the limit a new Monitor is refused rather than allowed to displace an older one. Your configuration — subject, criteria, trigger, delivery — survives untouched.

Back over the limit, they come back. A Monitor the system paused is restored oldest-first up to your new allowance; a Monitor YOU paused is never resumed by anything, at any plan, ever. That distinction is recorded on the Monitor itself rather than inferred, and the database clears it the moment you enable a Monitor by hand — re-enable one yourself and it is yours again.

A restore that your new plan cannot accept is reported rather than forced, and it does not cost anyone else their slot: restoring an hourly Monitor onto a daily-only plan is refused, and the next Monitor in line is restored in its place.

An unlimited plan is treated as unlimited — no Monitor is ever paused for being over a limit that does not exist.

2026-08-26

Added — a Monitor notification now tells you how to get every match, not just the handful it carries. A run counts every match and keeps a few, and those numbers are usually far apart: across production, 354 of 467 runs matched more than the run kept, the largest by 250 to 10. A Nigeria daily Monitor reported 139 matches and handed you ten rows, with nothing anywhere holding the other 129.

Webhook deliveries now carry `links.matches` — the absolute URL of that run's matched-item list — and `trigger.next_cursor`, the cursor to start it with. A receiver can walk the whole result set knowing nothing about Monitors beyond the envelope it was handed. Both are additions: the envelope version stays `1`, every existing field keeps its name and meaning, and a `monitor.test` delivery nulls them rather than pointing at a run that was never created. `trigger.next_cursor` starts at the beginning of the list rather than after the cards delivered inline, because those cards are a representative sample rather than a first page — deduplicate on `id` while paging.

Monitor emails now name the gap instead of leaving it to be assumed. The match count is followed by how many of them the email is actually showing, and the button says so — "Open all 139 matches" rather than "Open monitor run". An email that really is showing everything says neither.

Added — `get_monitor_run_matches` for agents over MCP, taking the same cursor and returning the same per-row status as the REST endpoint.

Each match carries both tellings: `as_triggered`, frozen exactly as the email or webhook asserted it, and `current`, fetched live, with a `status` relating the two. A run is a point-in-time answer and the warehouse keeps moving under it, so re-running the question later is not the same question — this way the difference is reported rather than silently served. A real example from the first production page: a story headlined "CIA Director makes unannounced visit to Moscow" was filed under the United States when the Monitor fired and under Russia by the time the page was read. The headline never changed, so a refetch would have shown only the second answer, with no sign the first had been sent.

A story that same-day reconciliation merged away reports `superseded`, and where the replacement is recoverable it carries `successor_id`. That mapping has been recorded in `story_merges` since we built same-day reconciliation; what made it impractical here was the shape of the walk, not the data — following it is per-id and up to four hops, so a hundred-row page would have been four hundred lookups. It is now done for the whole page at once, at most four lookups regardless of page size. A successor appears only when the chain ends on a story that is positively live: if it cannot be resolved the key is absent rather than null, because a key present and null would claim there is no successor when we simply did not find one.

An event that was merged away reports `gone` rather than `superseded`, and that is not an omission: an event merge deletes the losing row outright instead of marking it, so there is nothing left to point at.

2026-08-26

Changed — the Explore evaluation now starts when you create your account, not on your first API or MCP call. It was possible to sign up, use the web app for a week, and never receive the evaluation at all: the web app is not a metered lane, so the code that started the trial was never reached. Everything the evaluation promises — 1,000 query units and daily Monitors for 7 days — is now active from the moment you sign in.

Fixed — during an evaluation, your Monitor runs are drawn from the 1,000-unit evaluation grant rather than from the permanent 50-unit monthly sandbox. They were previously billed to the sandbox, so an evaluation quietly left you with a smaller allowance once it ended.

Fixed — the Free plan card on the pricing page showed Monitors as not included while describing the daily Monitor the evaluation grants. The two cards on pricing and subscription now answer that question the same way, from one shared rule.

The extension is 7 days, matching the evaluation itself; it was previously 14 in the code and described inconsistently across the pricing page, the subscription page and the button that applies it.

2026-08-26

Added — your Explore evaluation now tells you when it is ending. As the 7-day evaluation reaches its expiry you get one email with a summary of what you actually used — query units spent out of the 1,000 the evaluation grants, how many of those were API and MCP requests, how many Monitors you created, and how many days you used it — and a button to extend. Previously the evaluation simply stopped: nothing announced the expiry, and the extension existed on the subscription page with nothing pointing at it.

The extension adds 7 more days and can be used once. It runs from the day you ask rather than from the original expiry date, so an evaluation that has already lapsed still gets a full week. It asks what you are evaluating and roughly how much you expect to use — that is the whole form.

One email per evaluation, ever. If you extend before it arrives, it does not arrive; if you have unsubscribed from account email, it is not sent. Nothing changes if you do nothing: your account stays open on the free sandbox at 50 query units a month, with no card and nothing to cancel.

2026-08-25

Fixed — `GET /api/v2/search` returned nothing for some of the most-covered entities in the corpus, and only on the documented call. `?q=TikTok&limit=5` answered with zero results while `?q=TikTok&limit=5&country=USA` returned the right TikTok with 464 stories in the last 30 days: the canonical `q`/`type`/`limit` request quietly restricted results to registry ids, and adding any other parameter turned that restriction off. Entities that exist only in our news layer — TikTok, the Pentagon, the Senate, the Supreme Court, ICE, North Korea — were unreachable through the call our documentation and MCP tool recommend. The restriction is gone; every candidate now carries `monitorable`, which says whether that exact id can be used as a Monitor subject, so you can tell rather than being shown a shorter list.

Fixed — candidate ranking was decided by a field that is almost always zero. Results were ordered by news volume read from a frozen legacy layer that the search path skips whenever it already has a confident match, so in practice every candidate tied and the order fell through to a tiebreak with no opinion about relevance. `?q=Tesla` put "Tesla, Inc." (5 stories in 30 days) above "Tesla" (107) at an identical match score. Ranking now uses measured coverage — distinct resolved stories over the last 30 days, computed across both of our entity id-spaces and unioned over every id the entity resolves to — placed below match quality, never above it. On a 60-name industrial-supplier test, correct top results rose from 38 to 50 and empty responses fell from 12 to 3, with no name regressing.

Added — every candidate now returns `coverage_30d`, `match_score`, `monitorable`, and its sibling identifiers (`spine_id`, `wikipedia_url`), and `GET /api/v2/entities?search=` returns the same fields under the same names. `match_score` was previously published by one of the two and null on the other. `coverage_30d` is a measured count, not an estimate: a registry entity with no news identity reports 0 rather than being ranked as if unknown meant popular.

Added — an entity-filtered request that returns nothing now says which kind of nothing. `applied_filters.linkage` reports `unresolved` when the handle matched no entity at all, `none` when it names an entity we hold that nothing in the news layer links to, and `stale` when the entity is covered but not inside the window you asked for — with the id that does carry the coverage. Previously a typo, a real-but-unlinked entity and a quiet week returned byte-identical empty responses.

Changed — the entity binder behind Tone and Share of Voice now ranks candidates over a 30-day window instead of 90, counts only fully resolved links, and prefers an entity whose own name is what you searched for before preferring the one with more coverage. This can change which entity a name binds to on those pages: searching a parent company no longer binds to a better-covered subsidiary. It also means the coverage the binder ranks on is the same number the API now shows you.

2026-08-25

Fixed — a Monitor watching a named entity never matched anything. Not rarely: never, for every entity, on every schedule, since entity subjects shipped. It reported zero, stored a completed run and kept its Running badge, which is why it read as a quiet news week rather than a defect. Monitors on a country, a region, a facility or a place were unaffected and always worked, because those resolve no identifier.

The cause was an identifier mismatch inside the scheduled run. A Monitor stores the entity id you selected, and the scheduled path asked our resolved-coverage table for that id directly — but that table is keyed on the identifier our news layer assigns, not the one the entity registry assigns. Measured over three days, it held 8,862 and 17,014 entities under the two news-layer identifier spaces and none at all under the registry space, so the lookup could not match a single row. The public API had always bridged between the two; the scheduled path had its own copy of the lookup that did not, and had drifted. That copy is deleted. Monitor runs now resolve entities through the same code `/api/v2/events` and `/api/v2/stories` use, so a Monitor and the equivalent API call answer with the same rows.

What you will see: a Monitor on the European Union that reported 0 matches in an hour now reports 25; one tracking the United Nations and the Houthis together over a day reports 163. If you have an entity Monitor that has been quiet, it will start delivering on its next scheduled run — you do not need to recreate it.

Changed — Monitors now accept every entity identifier our resolver hands back, not only registry ids. Six of the twenty most-covered organizations in the corpus — including TikTok, the Pentagon, the Senate, the Supreme Court and ICE — exist only under a news-layer identifier and could not be made the subject of a Monitor at all; the entity picker dropped them without saying why, and the API rejected them with an error whose suggested fix could not work. All of them are selectable now, and the rejection message for a genuinely invalid identifier tells you to resolve the entity by name and shows a call that returns candidates.

2026-08-25

Fixed — `entity_refs` on Stories and Events was discarding most of what our entity resolver had already resolved, and companies were hit hardest. The serve layer admitted a resolved entity only when its id carried an `llm:` prefix, which is the id minted when the resolver CANNOT match a mention to a known entity; every successful match inherits the matched entity's own id and was therefore dropped. It also compared the extractor's vocabulary (`company`, `brand`, `ministry`, `regulator`, `party`, `ngo`, `union`, `campaign`, `armed_group`) against the three types the API publishes, with no mapping between them, so only `person` and `organization` survived — by coincidence of spelling. Measured over 2026-08-11..24, 12.2% of resolved entity links reached a customer.

What you will see: Stories serving no entities at all fell from 80.9% to 63.3% and Corporate Stories from 84.0% to 43.4%, with mean entities per Story up from 0.28 to 0.86; Events serving none fell from 62.1% to 23.1% over 2026-08-18..24. Roughly 1,900 additional Stories a day now carry at least one entity. A Story about a Tesla recall now returns Tesla, the State Administration for Market Regulation, XPeng, Xiaomi, Geely and Elon Musk, where it previously returned an empty list.

Changed — resolved entities now carry the identifiers that make them composable. Because the registry join was keyed on a Wikipedia URL the resolved rows never had, every such entity used to serve `id_space: "llm"` with `entity_id: null`, so it could not be chained into `/api/v2/entities/{id}`, `/api/v2/gov/awards?entity=` or any other endpoint keyed on our unified entity id. Those rows now resolve their URL from the entity registry and upgrade to `id_space: "spine"` (or `"wikipedia"`) with a real `entity_id` wherever the crosswalk has one. Entity `type` is now taken from the authoritative registry rather than from the per-link extractor label. No response field was added, removed or renamed.

Note — Stories and Events on dates already finalised keep their previously stored entity lists until those dates are rebuilt; newly processed dates carry the fix immediately.

2026-08-25

Changed — the Core endpoints now publish one way to ask each question. GET /api/v2/events went from 54 documented parameters across 71 spellings to 38 across 48; /api/v2/stories from 39/56 to 32/42; /api/v2/entities from 24/38 to 20/29; /api/v2/events/summary from 44/55 to 31/39 and /api/v2/stories/summary from 28/39 to 25/33. What was withdrawn is duplication, not capability: `date` (which is `date_start` and `date_end` set to the same day), the split `lat`/`lon`/`lng` spelling of `near`, `actor_country` (which is `source_actor_country` OR `target_actor_country`), `event_category` on Stories (which unions into `category`), the `include_entity_images` spelling of `include_images`, and the `query`, `keyword` and `name` aliases of `search` — `name` most of all, because on /api/v2/entities that word means an entity name and on /api/v2/events it does not.

Nothing was removed and no integration needs to change. Every one of those spellings is still accepted, still validated and still applied, exactly as before — they are no longer offered to a reader or an agent discovering the API for the first time. The same applies to `event_family` and `domain`, deprecated since 2026-05: our published stability policy has always said a deprecated parameter is no longer offered in the docs, the OpenAPI spec or the MCP schema, and that is now true. Both are still named, with their date and their replacement, in the parameter reference and on the API stability page.

Changed — four filters that describe our pipeline rather than the world came off the Core parameter list for the same reason: `incident_resolution` (which stage of duplicate adjudication an event reached), `geo_precision_min`/`_max` (how precisely a location was resolved), and the `systemic_importance`, `propagation_potential` and `market_sensitivity` bounds, each of which silently excludes every conflict event because only CAMEO+ events carry them. All three metrics keep their definition pages and still ship on every event card — they are measured and served, just no longer offered as filters. `significance`, `confidence`, `goldstein_scale` and `magnitude` remain the documented metric filters.

2026-08-24

Fixed — GET /api/v2/entities?search= now resolves a name across every entity universe we hold. The reference side — the GDELT Cloud spine (SEC/EDGAR, GLEIF, Global Energy Monitor), screening lists, China-Abroad, Epoch AI and government registries — was short-circuited to empty before ranking, so an entity that exists only in those registries could not be returned at all, however exactly you spelled its name. `search=Metso` returned "Louisville Metro Police Department" and now returns Metso; `Eaton` returned a California wildfire and now returns Eaton Corporation; `ABB` returned Abbott Laboratories; `Jabil` returned the Bureau of Jail Management and Penology; `Flex` now returns Flex Ltd. and `Infineon` returns Infineon Technologies. A row surfaced this way still reports its coverage metrics from our resolved layer, so a real company with no coverage in your window honestly reports zeros rather than a fabricated number.

Changed — entity results are ordered by match quality, taken from the same resolver GET /api/v2/search uses: a verbatim token hit first, then match tier, then prominence. Article volume no longer sorts above the name you asked for. Every row now carries `match_type`, `match_reason` and `match_score` so the ranking can be audited rather than trusted, and ranking is applied before paging — `?search=ICE&type=organization` previously returned a different first result at limit=1, limit=3 and limit=5.

Fixed — GET /api/v2/entities rejects a query parameter it does not declare, with 400 UNKNOWN_PARAM and a suggested spelling, as the rest of the v2 surface does. `?entity_search=Infineon` — a real parameter name on /exposure and /entity-tone — returned HTTP 200 and Donald Trump, the unfiltered global top entity, with nothing in the response saying the search had been dropped. In the same pass `entity_type=` is now accepted as an alias of `type=`: /api/v2/meta/enums publishes that vocabulary under the id `entity_type`, so a caller reading the enum catalogue was sending a parameter name that was silently ignored.

Fixed — a Monitor now shows every scheduled check, not only the ones that fired. A run is recorded only when a Monitor triggers, so one that checks hourly and correctly matches nothing showed an empty history forever — indistinguishable from a Monitor that had never executed. GET /api/v2/monitors/{id}/runs now returns a `checks` array beside `runs`, one row per execution with `checked_at`, `match_count`, `triggered` and `execution_time_ms`. `runs` keeps its exact meaning and shape.

Fixed — a Monitor read that fails in the analytics warehouse returns 503 MONITOR_WAREHOUSE_UNAVAILABLE with `details.retryable`, instead of an opaque 500 Monitor operation failed. A cluster that was briefly busy and a Monitor that can never work are different answers to "will this fire before I depend on it", and a retry policy has to tell them apart. Monitor test delivery also reports each channel separately — an email-only Monitor was told `not_configured` inside a 200 with `success: true`, which was true of the webhook it does not have and false of the email it does.

Fixed — GET /api/v2/share-of-voice explains a small share when the denominator is the reason for it. A literal `topic=` denominator selects stories whose headline literally contains that word, so an entity central to the conversation but reported without it reads low — honestly, not as a data gap. `coverage.note` now says so on sparse and intermittent results, not only when the share is zero, and points to the semantic `query=` denominator that measures the same entity across the broader conversation.

Fixed — the MCP `search_entities` tool reported zero coverage for every entity. It defaulted to a one-day window, and that branch also clamped the coded-at window to yesterday against an exclusive upper bound, excluding everything ingested in the previous 24 hours. Donald Trump returned 0 events over MCP against 2,014 over REST; the two now agree exactly.

2026-08-24

Fixed — entity Monitors now use the dependable signal available today: explicitly labelled broad coverage, with linked Events where present. Preview and execution use the same resolved entity scope as the Core Events and Stories APIs. New `material` or `actor` configurations are rejected as unsupported instead of silently degrading; use the coverage trigger followed by Query Unit-backed investigation when material involvement matters.

Fixed — Unicode and percent-encoded spellings of the same Wikipedia URL now resolve to one entity identity. Search no longer returns separate Nestlé news profiles whose coverage and tone disagree, and spine IDs bridge to the normalized media profile used by Tone, Share of Voice, Events, Stories and Monitors.

Fixed — Atlas GPR `as_of` now applies to the normalization baseline as well as the observation. A historical request cannot use a baseline frozen in its future; if none existed by that vintage, raw vintaged shares remain available while pulse and band are withheld. Atlas also publishes its 2026-04-05 history boundary in `meta.coverage`, separately from the per-reading event threshold. Both constructions now disclose when a row used the temporary cross-generation pooled baseline, and the response-level baseline describes the first returned row rather than a different fallback instrument.

Corrected — Share of Voice now publishes the dependable metric we can support from canonical serving records: an entity’s share of settled Stories in an explicit denominator. The previous article-share and weighted-share fields were withdrawn because article-level attribution was reconstructed outside the serving record and prominence came from upstream GEG salience rather than a first-party relevance judgment over every entity–Story pair. The published example also includes the denominator required by the endpoint.

Fixed — GET /api/v2/meta/query-units now returns the authenticated organization’s current allowance, consumption, remaining Query Units and reset window, as its published contract promised. Its cost model now lists Monitor execution explicitly with a zero multiplier; legacy Alert execution remains separately identified.

Fixed — observed_start is inclusive and observed_end is exclusive. Equal endpoints now return 400 INVALID_DATE_RANGE instead of an unexplained successful zero, and the point-in-time guide uses the next calendar date to include a complete final day.

Fixed — if webhook signing is unavailable in a deployment, Monitor create and update return a typed 503 MONITOR_WEBHOOK_UNAVAILABLE before saving a partial webhook configuration, rather than an opaque 500 after mutation. Webhook entitlement is now enforced before DNS resolution of a caller-supplied hostname.

Documented — Monitor Preview, run, replay, batch and delivery responses now have typed OpenAPI schemas and current examples instead of legacy Alert fields. The docs distinguish execution counts from retained and inline samples, disclose bounded semantic counts explicitly, report per-id batch outcomes, and make exact replay explicit: page every day-bounded request, apply its half-open timestamp filter, then union and deduplicate multi-entity results.

Fixed — the homepage live tape now reads the deduplicated live Event stream for its rolling observation window. A delayed settled snapshot can no longer make Events by country, Event types and Coded metrics silently disappear while the current Events API is returning data.

2026-08-23

Added — Monitors replace Alerts as the supported automation surface. Create a structured Monitor around an entity, facility, place, geography or topic; choose Events, Stories or both; then deliver new matches by email. Watch and higher plans can also use signed webhooks. Scheduled Monitor checks never consume Query Units; an accepted on-demand Preview consumes one. Volume spikes and higher-confidence actor/material attribution are deliberately deferred rather than exposed before independent validation. Existing Alert rules, histories and identifiers continue to work as compatibility data under /monitors.

Changed — plans are now Explore, Builder ($59/month), Watch ($149/month), Analyst ($399/month), Intelligence ($899/month) and Enterprise. New defaults are Builder 2 daily Monitors / 1,500 QU, Watch 10 hourly / 3,000 QU, Analyst 30 hourly / 10,000 QU, and Intelligence 75 hourly / 25,000 QU. A Monitor can cover up to 25 compatible entities or countries that share one question, cadence, recipient set and response process. Existing paid organizations retain their exact prior effective Query Unit allowance.

Changed — Explore is an evaluation followed by a small permanent sandbox, not a production Free tier. A user-started evaluation provides 1,000 total Query Units and daily Monitors for seven days, with one 14-day extension available after sharing a use case and expected usage. When it ends, the account keeps 50 Query Units per month and its Monitor configuration stays saved but paused.

2026-08-23

Every list and summary response now declares its own coverage envelope. GET /api/v2/events, /events/summary, /stories and /stories/summary carry `meta.coverage` with `start`, `end` and a `warnings` array. Ask for a window that begins before the corpus does and you now get `requested_window_precedes_coverage` and a sentence saying an empty result means NO DATA — previously that request returned HTTP 200, `success: true`, an empty array, and the out-of-range dates echoed back under `applied_filters` as though they had been honoured, which is indistinguishable from a genuinely quiet window. Coded events begin 2026-03-01 and clustered stories 2026-03-08; those dates are also now on the Data Status page, which until today was scoped entirely to the last 30 days and never said how far back history went.

Restricted-party screening stops answering `no_match_found` to two questions it cannot answer. GET /api/v2/screening/match now returns `screen_status: "inconclusive"` with `inconclusive_reason: "as_of_precedes_coverage"` when the requested `as_of` predates our list history (which begins 2026-06-13), and `screen_status: "out_of_scope"` when the subject is a natural person — every list we ingest is institution-only, so a person was never screenable. Both were previously byte-identical to a clean screen. Every response also carries `subject_scope` and `coverage_window` so the limits are machine-readable rather than prose. Relatedly, GET /api/v2/search now returns `sources.sanctions: null` — never `false` — for a person-typed entity, with a `source_scope` block explaining what the null means, and GET /api/v2/exposure attaches a caveat to an empty result instead of returning a bare `[]`.

GET /api/v2/stories/{story_id}/articles returns the `url` field its published schema has always declared. It was absent from every row, along with `id` and `article_date`, because the query named those three columns ambiguously across its joins and the response mapper read the unqualified names. This is the last hop of the documented evidence chain, so an underwriting note built from it could show a headline and a bare domain and nothing to click. The same endpoint now answers `404 STORY_MERGED` with a `successor_story_id` for a merged story, matching its parent endpoint, instead of an empty `200` that read as "this incident has no sources".

Fewer fabricated zeros. GET /api/v2/share-of-voice emits `null` for `avg_tone_score` and `avg_risk_score` on days it observed nothing, rather than `0` — the bottom of both scales. GET /api/v2/events/summary with `group_by=date` now emits a zero bucket for a quiet day inside coverage instead of dropping the row, so a daily panel has no invisible holes, and it no longer publishes the whole metric tree twice as both `metrics` and `metric_stats`.

Maritime. GET /api/v2/maritime/gaps accepts `max_gap_hours` and `sort` (`longest` | `shortest` | `recent`); previously it had only a floor and a fixed longest-first order, so the entire first page was three-week silences and the operationally interesting 12-48h band was unreachable. GET /api/v2/maritime/chokepoint-watch no longer folds absent AIS coverage into `risk_level` — a chokepoint we cannot see is uncertain, not dangerous, and the old scoring ranked every dark chokepoint above every lit one. Coverage now travels beside the level as `blind_spot`, `risk_level_basis` and, where relevant, `risk_level_qualifier`. The Maritime endpoint group is also visible in the API Arena, along with every other Open Feeds group; the Arena previously showed customers only Energy.

GET /api/v2/intelligence/posture now reports `as_of_integrity` on any point-in-time request. Its event counts respect `as_of`, but the cross-sectional baseline they are normalized against is not vintaged, so a reading can embed information from after the requested date; the response names the baseline window and the number of look-ahead days. The published parameter description promised "no look-ahead" and has been corrected. `window` also now accepts both spellings (`30` and `30d`) on `/intelligence/posture` and `/intelligence/coverage`, which previously disagreed about what the same parameter meant.

An unrecognised `/api/v2/*` path returns a JSON 404 with `code: "UNKNOWN_ENDPOINT"` and a `did_you_mean` list, instead of roughly 111 KB of HTML that crashed a JSON parser. Entity tone keyed by canonical id now hydrates the entity's display name, type and Wikipedia URL rather than echoing the id back. And the public demo pages compute a genuinely rolling window: all three had a hard-coded week in May 2026 under a comment reading "7-day rolling weekly window", while stamping the page as refreshed today.

2026-08-22

Correction: the per-language entity tone breakdown announced on 2026-07-24 as `entity_coverage[].by_language` never returned anything. It answered `[]` for every entity on every request that asked for it, at HTTP 200, from the day it shipped — the code that assembled it read six columns its own query did not produce, so every row was discarded silently. If you built on that field you saw an empty array and had no way to tell it apart from an entity with no coverage. We are sorry; it was our bug and nothing about your query was wrong.

The same numbers were being returned correctly the whole time, one level up, as the `language_breakdown` field on GET /api/v2/entity-tone and GET /api/v2/entities/{entity_id}/tone — which is what the Media Tone page has always rendered. `language_breakdown` is always present, needs no parameter, and since yesterday also carries the news/social split (`avg_news_tone_score`, `avg_social_tone_score`) that `by_language` never had.

What changed today: `entity_coverage[].by_language` and the `group_by=language` parameter are gone rather than repaired, because a second per-language view of the same measurement is a thing that can disagree with the first. `group_by=language` is still accepted and simply has no effect — your existing calls return exactly what they returned before, since the breakdown was always computed either way. Read it from `language_breakdown`.

On the entity detail response, `entity_tone.by_language` (`GET /api/v2/entities/{entity_id}?include_tone=true`) is now fed from that working field, so it carries real rows for the first time. Its item shape follows `language_breakdown`: `language`, `avg_tone_score`, `avg_news_tone_score`, `avg_social_tone_score`, `article_count`, `news_article_count`, `social_article_count`, `scored_rows` — in place of the `mean_tone` / `mean_risk` / `confidence` / `series` fields the old schema described and never once emitted. Per-language risk and confidence, and the per-language daily series, are not currently published anywhere; ask if you need them.

2026-08-22

Media tone is now reported separately for news coverage and for social posts. Until today one model call read both kinds of evidence together and returned a single blended score, and our own documentation said a score was "not separable into a news and a social component after the fact". It is now: the same call returns the blended headline plus `news_tone_score` and `social_tone_score`, each scored over that source alone, on the same -100..100 scale.

Where to find it on /api/v2/entity-tone and /api/v2/entities/{entity_id}/tone: per day in `rows` (`avg_news_tone_score`, `avg_social_tone_score`), per entity over the window in `entity_coverage` (`mean_news_tone`, `mean_social_tone`), per story in `evidence_samples` (`news_tone_score`, `social_tone_score`), and per language in `language_breakdown` (`avg_news_tone_score`, `avg_social_tone_score`). `evidence_samples` and `language_breakdown` are now described in the OpenAPI spec as well, which they were not before.

Read each component against its own denominator, which is published beside it — `scored_news_story_count`, `scored_social_story_count`, `news_article_count`, `social_article_count`, `news_evidence_count`, `social_evidence_count`. Social evidence is attached only to entities already present in the news stream and typically backs a small minority of the scored stories, so a social tone without its story count invites a conclusion the evidence does not support.

The social reading is deliberately NOT capped by the blended one. The blended score continues to weight news above social, so where the two diverge sharply — the press mild, the timeline severe — that gap is the finding rather than an inconsistency.

This is forward-only and cannot be backfilled. Scores written before today report `null` for both components, never `0` — zero is the middle of the neutral band, and reporting it would assert a reading nobody took. The counts distinguish the two kinds of absence: a null component with a non-zero item count means the score predates the split; a null with a zero count means that source contributed no evidence to that story.

The blended `tone_score` is unchanged in definition and remains the headline. Existing fields, filters and response shapes are unaffected.

2026-08-22

Entity identity: names that merely share their initials are no longer merged. A mention was being bound to an unrelated registry entity whenever the two names reduced to the same acronym — "Bharatiya Janata Party" resolved to a British politician, "Alexandria Ocasio-Cortez" to an Indian brokerage, "Supreme Court of Iran" to the Supreme Court of India, and a Sao Paulo health app to a US Senate candidate. Such a match is now adjudicated instead of accepted, so /api/v2/entity-tone, /api/v2/entities/{entity_id}/tone, /api/v2/share-of-voice, /api/v2/entities and the MCP tools return stories that belong to the entity you asked for.

You may notice this two ways. An entity whose coverage was being absorbed by a namesake can start returning results where it previously returned none — an empty tone response was in some cases the symptom, not an absence of coverage. And an entity that was absorbing others will lose the stories that were never its own, so its story counts and mean tone can both move.

Media tone evidence: a Bluesky post must now be about the story it is attached to. Social evidence was selected by entity name over a rolling seven-day window and reused across every one of that entity's stories, so a story could be scored partly on reaction to a different story. Posts are now matched against the story's own content and cannot predate it. Tone scores for affected entity-days will move.

New parameter: /api/v2/entity-tone and /api/v2/entities/{entity_id}/tone accept `category`, the same story-category vocabulary as /api/v2/share-of-voice?category=. It narrows the time series and the evidence samples together. An unrecognised value returns 400 INVALID_ENUM with accepted_values; omitting it means all categories, which is what these endpoints have always returned.

Media Tone page: the tone score and the window it covers now lead the entity card, the tone and risk gauges name their axes and use the bands the scoring rubric defines, and card borders are legible across the app. Filter controls that never narrowed the query have been removed rather than left looking active.

2026-08-22

Changed — /api/v2/events/summary and /api/v2/stories/summary now reject a query parameter they do not declare, with 400 UNKNOWN_PARAM and a suggested spelling, exactly as their list twins have. Both endpoints published a strict contract that nothing enforced: `?countries=NGA` — one character off `country` — returned HTTP 200 and the WORLD's 57,806 events where Nigeria's figure was 2,955, while /api/v2/events answered 400 for the identical typo. `applied_filters.ignored` did report it, but only to a caller who reads that field.

Changing for integrators — five parameters the two summaries accepted and never read now return 400 UNSUPPORTED_PARAM naming the list endpoint instead: `sort`, `cursor`, `offset`, `include_images` and `include_entity_images`. A summary returns buckets, so there was nothing for them to order, page or illustrate; being on the allowlist meant they were echoed back as APPLIED, so paging a summary with `offset` returned page one every time under a response that agreed the offset had been used. `limit` still bounds the number of buckets. In the other direction, `languages`/`language` were applied by both summaries all along and are now declared, documented and generated like every other filter.

Changed — an entity filter whose material attribution is not yet built for the requested window now returns broad story coverage and SAYS SO, rather than failing. `applied_filters` carries `entity_match: "coverage"`, `coverage_fallback_applied: true` and a sentence explaining what the rows are. Sending `entity_match=material` explicitly still returns 503 ENTITY_ATTRIBUTION_UNAVAILABLE — if you asked for material by name you get a straight answer, not a substitute.

Fixed — the same unavailability could also produce an empty HTTP 200. The availability check sat behind entity resolution, and entity resolution is scoped to the requested window, so an entity with no coverage in that window skipped the check entirely and received zero rows next to our own note saying the filters were understood and nothing matched. Whether a capability is available never depended on the entity; it now cannot depend on how much news that entity made.

Fixed — /api/v2/events/summary returned an untyped 500 INTERNAL_ERROR where /api/v2/events returned 503 ENTITY_ATTRIBUTION_UNAVAILABLE with `details.retryable` for the same condition. A retry policy written against one surface behaved wrongly against the other. Every v2 endpoint now answers that condition identically.

Fixed — `include_total=1` produced no `pagination.estimated_total`, was echoed back as though it had been applied, and never appeared in `applied_filters.ignored`; `include_total=True` was accepted by the contract and then silently dropped. Booleans are `true` or `false` in any casing, and anything else is now a 400 INVALID_BOOLEAN that says so. If you were sending `1`, send `true`.

Fixed — the MCP `summarize_events` and `summarize_stories` tools reported the per-event AVERAGE under the field name `article_count`, which is the total everywhere else. For 2026-07-29 an agent read 2.589 where the REST bucket says 321; over a 30-day window, 89 articles against 8,399. Both numbers are now published, under the names REST uses. Three neighbours went with it: story summary buckets reported no `count` at all, the four CAMEO+ metrics were dropped from every digest, and a nested aggregate was emitted where a number was promised.

Added — a published API stability and deprecation policy, at docs.gdeltcloud.com/reference/stability. At least 30 days' notice before a breaking change or an endpoint removal; what changes without notice, and why data corrections are on that list; what deprecated, retired and removed each mean and how to tell them apart from a response. Its inventories are generated from the same contract the API enforces, so the page cannot outlive its subject.

Added — the changelog is now an RSS feed at /changelog/feed.xml, linked from this page's head. It was previously the only channel for a breaking change and the only way to read it was to remember to visit it.

Fixed — the parameter reference miscounted which endpoints share a parameter, because a name accepted on one endpoint and rejected on another was recorded once and judged by whichever it met first. `as_of` was missing from the shared table entirely and several geography parameters were overcounted.

2026-08-21

Updated — Energy Data now serves the July 2026 Global Coal Plant Tracker and August 2026 Global Energy Ownership Tracker. The refresh contains 14,674 coal units representing 5,493,824 MW and 26,943 ownership entities; both releases were loaded through validated staging tables and atomic warehouse exchanges.

Changed — entity filters on Events and Stories now mean material involvement by default. Every returned row carries the role, decision, confidence, resolution method and supporting evidence that caused it to match. The former broad Story co-occurrence behavior remains available explicitly as entity_match=coverage; the API never silently falls back to it.

Changed — event_date is the evidenced occurrence date. Events now separately disclose observed_at, event_date_basis and event_date_evidence, and unknown fatalities or canonical Story article counts remain null instead of becoming zero.

Changed — Facilities now default to one canonical physical site. A site reports its source registry units, a status breakdown and mixed when those units conflict; granularity=unit exposes the source rows, and a legacy f_ unit id resolves to its s_ parent site.

Changed — Screening separates candidate-retrieval score from identity confidence. Exact verified identifiers and aliases are deterministic; gray candidates are independently adjudicated and remain inconclusive until calibrated, while rejected candidates are not counted as matches. min_match_confidence is canonical and threshold is a deprecated alias for one compatibility period.

Added — Alerts can target one or more terminal entity IDs, a Facility, or an explicit latitude/longitude/radius. Entity alerts use material matching and collapse duplicate incidents by default, and the preview reports query units from the actual number of alert lanes.

Changed — descriptor-backed endpoint families now return 400 UNKNOWN_PARAM for undeclared query parameters, with a suggested spelling. OpenAPI, docs and Arena fields are generated from those executable descriptors; supported deprecated aliases remain declared during their compatibility period. Remaining legacy families are explicitly inventoried and cannot be described as contract-complete until they adopt the same runtime.

2026-08-20

Fixed — a gated source flag on /api/v2/search is now absent rather than false when you are not entitled to it. Yesterday's note said `gov` "reports availability only to callers entitled to it"; that was the intent and the published spec, but not what the code did. It set the flag to `false`, which is an answer — it says we looked and the entity has no such records — when in fact we had not looked on your behalf. A caller on Professional searching for Anduril received `sources.gov: false` on RTX Corporation, which holds 111 current federal awards worth $44.3B. The same row on an entitled key returns `true`. This affected `sec`, `sanctions`, `china` and `epoch` in the same way and for longer; `gov` is simply the one that made it visible.

Changing for integrators — test with `'gov' in sources`, not `sources.gov === false`. An absent flag now means the source was not checked for you; it never means the entity has no records there. If you were treating `false` as evidence of absence on any of the five gated sources, that reading was wrong before this change and is impossible after it. Nothing that was `true` has changed, entitled callers see exactly what they saw, and the identifiers were already being withheld correctly — it was only the flag that disagreed.

Changed — entity risk scores are recalibrated, and a risk series that spans today mixes two calibrations. The tone and risk scorer moved to a stronger model tier (it applies a seven-band rubric with worked examples, and was running on a tier below the one that rubric was written and measured for). Scored on identical evidence, the new tier returns risk about 7 points lower on a 0-100 scale, a difference that is statistically real rather than noise; tone scores are unchanged. Rows written before 2026-08-20 21:30 UTC carry the old calibration and have not been rewritten — they are not wrong, they are a different instrument. If you compare entity risk across that boundary, expect a step, and prefer comparing within one side of it until the history is re-scored.

Fixed — the loader-audit panel in the ingest console had never worked, in any environment. A column alias shadowed the column two aggregates sorted by, so the query failed on every call and an over-broad error handler reported it as "this table has no load audit". Eleven data lanes showed no loader status where they should have shown a pass and a date; twenty-eight now report one. This is an internal console fix with no API surface.

2026-08-20

Fixed — an event id that was merged away now tells you what replaced it. When two coded events are adjudicated duplicates we keep one and remove the other, and until now the removed id simply stopped resolving: /api/v2/events/{id} returned a bare 404 and the public event page showed a not-found. There was no way to find the surviving event, so an integration polling a stored id just saw it go dark — one of them polled the same retired id 133 times over six days. That id now returns 404 with code EVENT_MERGED and a successor_event_id you can follow, and /events/{slug} redirects to the surviving event instead of dying. EVENT_WITHDRAWN still means what it always meant: the event was suppressed and there is no replacement.

Fixed — the probe behind that answer could not see the most common case. It looked for the retired id on the link table, but a merge re-points that column to the surviving event, so a merged-away id appeared nowhere and was indistinguishable from a typo. It now also matches the id the link records as its origin.

Fixed — when two events covering the same incident were merged, we could keep the wrong one. The choice was made on accumulated evidence — how many clusters an event had absorbed, how many articles its story held — without checking whether that story was still live. On 2026-08-20 the Evergrande sentencing existed as two stories; the story layer correctly merged them at 05:54, and the event merge ran eight hours later and kept the event belonging to the story that had been superseded and held zero articles, deleting the event of the live 85-article story. Whether an event's story is still live is now the first thing the comparison asks. Where both are live nothing changes.

Note — ids that were retired before this shipped can be recovered from links we already store, and that history is being backfilled. A small number cannot be: about 1 in 75 retired ids maps to more than one surviving event, and there the honest answer is still a 404 rather than a guess.

Added — an event can now name more than one actor on a side. A court that sentences a founder and in the same ruling fines two companies has three targets, and until now we recorded one: the other two simply were not in the data, so filtering for corporate legal action against either company did not find the event. `actors[]` now carries them all, each with its own country. Every actor gained a `primary` field — true for the one entity the event is chiefly about on that side, which is the one `source_actor` and `target_actor` and every existing filter still refer to. Nothing that worked before changes; the array is simply no longer capped at two.

Note for anyone reading actors[] — it could previously hold at most two entries, and some code assumes that. It can now hold more. Conflict-family events are unaffected: they record associated actors differently and are unchanged. Co-actors are recorded going forward, not backfilled, so events coded before today carry none.

Measured before shipping — 24 real clusters coded twice with the feature off and once with it on, from identical cached source text. Every field we already published (scope, event code, domain, the primary actors, the title) moved LESS between off and on than it moves between two identical off runs, so there is no measurable change to anything that existed. Co-actors appeared on 16% of events; every one was checked by hand.

Fixed — an actor that failed to resolve because of a network timeout stayed unresolved forever. When we link an event's actors to entities, the answer is cached so a miss does not cost a slow lookup on every run. But a timeout is not an answer about the actor — it is a statement about the network at one moment — and it was being kept as though it were permanent. 7,866 actors were in that state; a sample found roughly one in five is a real, resolvable entity, including public figures who simply happened to be looked up during a blip. Those are now re-checked weekly. Verdicts that genuinely are a property of the name, such as "this is a job title, not an entity", are unchanged and still cached indefinitely.

Not changed, and worth saying — an actor that was cached as unknown to our entity registry is still cached that way. Re-checking those looked cheap and measured out otherwise: it would push a fifth of the work back onto the slowest stage of the pipeline for a yield under one in a thousand, and because a resolution is kept permanently once made, a wrong one would be too. That needs a precision measurement first.

Changed — QU top-up pricing has doubled on Builder, Analyst and Intelligence. Builder is now $12 per 250 QU, Analyst $60 per 2,000, Intelligence $160 per 10,000. Top-ups are an overflow valve, not a cheaper way to buy volume, and the old rate had drifted well below the in-plan rate on every tier. The maximum of three top-ups per period is unchanged, so the ceiling on an unexpected bill still sits at roughly a third of plan spend, and you can turn top-ups off entirely from your subscription page.

Fixed — semantic search now tells us when it breaks. `search=` on /api/v2/events, /api/v2/stories and /api/v2/search embeds your query before it runs, and when that upstream call failed the endpoint returned a correct 503 and nothing alerted anyone — so the feature could stay down for a day or more. It now pages us the moment the cause is one only we can fix, and the underlying reason is recorded rather than collapsed into a single generic message.

Fixed — /api/v1/entity-geg returned a bare 404 instead of 410 Gone. Every other retired path names its replacement in the message, in details.replacement and in an RFC 8594 Link header; this one was inventoried when the v1 surface was retired and never got its stub, so the handful of callers still hitting it got an answer indistinguishable from an outage. It now points at /api/v2/entities/{entity_id}.

Fixed — a plan gate reached through the MCP was recorded as an error rather than as a plan restriction. This never changed what you received (still a 403 naming the feature and the upgrade path); it only affected our own reliability reporting, where upgrade prompts were being counted as platform failures.

2026-08-19

Added — /api/v2/search now reports a `gov` source. A hit carries `sources.gov: true` when the entity has a US government identifier (its SAM UEI, the key USAspending awards resolve on) or a government record (a federal award, or a FARA registration on either side of the foreign-agent relation). Anduril Industries is the case that prompted it: the response already returned `US_SAM_UEI: KC3CH2MSK7Q3` among its identifiers while the source map said it carried no government data. Like the other paid sources, `gov` reports availability only to callers entitled to it, and the UEI is redacted alongside the flag rather than left behind. EPA ECHO enforcement is deliberately not part of this signal — operator-name attribution over-matches, and a source flag is an attribution claim.

Fixed — the Unified Search box in the API Arena. `q` is the parameter the endpoint cannot run without, and it was rendering inside the collapsed Refine section: you opened the endpoint that is a search and saw no search field. The universe selector, which decides which corpora are searched at all, was collapsed with it. Both now sit at the top of the form. The same omission had buried the primary input on Screening Match, Facilities and Energy Owners; those are fixed too. This is a console fix only — no API behaviour changed.

2026-08-18

Added — bulk downloads. Every coded event we serve is now also a file: one per calendar month plus a rolling full-history cut, in Parquet and gzipped CSV, at /downloads or through /api/v2/bulk/files. 172,213 events across 171 settled days, March 2026 to now. It is the same table /api/v2/events reads, so a row in a file and the same row from the API agree field for field — we check that on six dates spanning the range before publishing, comparing the exported projection against the live serve path row by row. Included on Intelligence, Enterprise and the new Academic plan.

Added — an Academic & Research plan. Free, verified access for individual researchers and journalists: every data surface at 5,000 query units a month, five daily Monitors, API, MCP, Monitor webhooks and bulk downloads, with no Briefs. It is invite-only rather than purchasable — request it from your subscription page and a person reads every one. Previously this was a card on the pricing page whose only mechanism was an email address.

Changed — the bulk files publish their own coverage rather than implying it. Each one reports settled days against calendar days, so an in-progress month reads 18/31 instead of looking complete, and a sha256 you can verify before loading. A month is only whole when those two numbers agree.

Note for anyone loading the files — a null metric is not a zero. The conflict family carries no magnitude, systemic-importance, propagation or market scores, and the CAMEO+ family carries no fatalities, because those questions were never asked of those events. Coalescing them to 0 on import invents measurements that were never taken. civilian_targeting is three-valued for the same reason: true, false, and null where no coder evaluated it.

Changed — /api/v2/stories/summary is now a Story summary. The 43 linked-event metric rollups (avg/min/max of goldstein scale and severity, magnitude, systemic importance, propagation potential, market sensitivity, confidence, and avg_recency_score) have been removed. A Story has no metrics of its own; those belong to its linked Events, and /api/v2/events/summary is where they live — it supports every group_by this endpoint does, plus two more, and accepts the same entity scope. Every response now carries a notice field naming it.

Fixed — and this is why they were removed rather than moved. Those averages were wrong. A story with no linked events contributed a literal 0 rather than a null, so the not-null guard never fired and each average was spread over every story in the bucket instead of only the stories that had events. Measured over 2026-08-14..16, avg_linked_event_magnitude read 0.4693 where the event-level figure was 2.9316 — understated by 84% — on the default, most-common call. If you were reading those fields, the numbers you had were not the numbers you wanted, and the events endpoint computes them per event, so they will not match what this endpoint used to return.

Kept — everything that is genuinely a property of a Story: story and article counts and their distributions, significance (an article-volume measure, not an event rollup), counts of linked events, stories with events, fatalities, and country/region counts. No request that worked before returns an error now; the response is narrower, not stricter.

Changed — ?country= on Stories now finds Stories with no coded Event. A Story has no coordinates of its own, so the filter was answered entirely through its linked Events, which meant ?country= silently also meant has_events=true and roughly four in five Stories were unreachable by any country filter, in any spelling. Stories now also match on their own attributed country. Over 2026-08-14..16 that took the reachable set from 5,386 to 24,207 of 25,463 Stories — about 4.5x. Nothing that matched before stops matching; this only adds.

Scope — combining country with an Event-scoped filter (event_category, subcategory, admin1, bbox, domain, civilian_targeting) keeps the Event-only definition, because those ask a question about the Story's Events and a Story with none cannot answer it. Attribution begins 2026-07; query a window before that and the filter behaves exactly as it did.

Changed — group_by on /api/v2/stories/summary now buckets Stories by the same country the filter matches on. Previously the filter and the grouping disagreed: you could filter to a country, group by country, and not find it, for exactly the Stories with no coded Event. Two numbers move as a result. On a date bucket, country_count and region_count rise (167 to 193 countries on 2026-08-14) because those Stories now have a country at all. Inside a country bucket, region_count falls sharply — United States read 10, now reads 1 — and that is the correction: a United States bucket holds US Stories, which are in one region; the old number counted the regions of their Events, which can be anywhere.

Faster — date, country, region and continent summaries now read the pre-settled snapshot. Same numbers to within 0.1 to 0.3 percent, and the category and subcategory dimensions are unchanged because those group by linked-Event taxonomy.

Fixed — the docs said /api/v1/* was still supported. It is not, and has not been since 2026-08-12: every v1 path returns 410 Gone naming its v2 replacement in the message, in details.replacement, and in an RFC 8594 Link header. Three pages carried the old claim. /api/v2/events?family=conflict and ?family=cameoplus are strict supersets of the two v1 event routes.

Fixed — the docs said metric_version was stored but not returned by the API. It is returned on the event card whenever it is set, so it is the direct way to tell a v2-scored event from an older one.

Changed — the event metric reference is now one page per metric. /reference/metrics keeps the design rule, significance in full and a summary of each of the four scored metrics; magnitude, systemic importance, propagation potential and market sensitivity each have their own page with the sub-factors, the anchors, the NULL rule and what that metric does not claim. Existing #anchor links still resolve. The cross-cutting caveats that were repeated on every metric — the frameworks we adapt, how thin the registry coverage is, and the run-to-run noise floor — now live once, on /metrics/limits.

Corrected — the coding-latency explanation. It said a Story had to accrete corroboration before it could be coded, and named that as the main reason events are coded after the day they happened. That is not how the pipeline works: single-article clusters are a first-class coding path and are most of what we code. Measuring latency from the earliest contributing article instead of the one the coder read moves the median by 32 seconds. The real causes are the hourly ingest cycle, publication lag in the sources, and the fact that event_date is a date rather than a timestamp. The page now also names observed_start / observed_end, which is the point-in-time filter on the API.

2026-08-17

Removed — the five-key limit on API keys. It was never a plan limit: nothing sold more of them, and nothing in the interface counted down toward it, so you met it as a red error at the moment you were trying to integrate. There is now a safety ceiling of 100 live keys per person per organization, which exists only so a runaway script cannot fill the table. Revoking a key has always freed its slot; an auto-disabled key still occupies one, because it is re-enableable and therefore still yours.

Changed — revoked keys have moved out of the main list on the API Keys page into their own collapsed section. A revoked key is permanent and carries no controls, so it was inventory-shaped dead weight sitting between the keys you actually use. It is still there, still counted, still readable as an audit trail of what was issued — just folded away by default.

Changed — Connect now has three doors instead of two: Plugin, MCP and REST API, in that order. The plugin path (one command in Claude Code or Codex) was previously only documented on a page that no longer exists. The API key panel moved out of the REST section and now sits above all three, because every route in needs the same credential and the previous layout told MCP users to go looking for it under a heading about applications.

Changed — the code samples on Connect are now syntax-highlighted, default to Python, and are generated from the same contract the API validates against, so the endpoint path and parameters in a snippet cannot drift from the ones the service accepts. They also read your key from a GDELT_API_KEY environment variable rather than inlining it, so you can paste them straight into a repository. One correction that came out of it: the FastMCP example called a method that does not exist on the client (get_tools); it is list_tools.

Fixed — the key picker on Connect read from a pre-organization code path, so a member of a shared organization could see a different set of keys there than on the API Keys page. Both now read the same organization-scoped source.

2026-08-16

Added — you can now ask who acted on whom. /api/v2/events and /api/v2/events/summary accept source_actor_country, target_actor_country and actor_country. Until now country was the only geographic filter, and it matches the event's location OR either actor's origin — so "China acting on the West" could not be expressed and had to be reconstructed on your side from each event's actors array. Measured over thirty days: country=CHN returns 1,995 events, of which 129 are China-source against a Western target. You were downloading fifteen rows for every one you kept, and writing the classifier that decided which. The new parameters accept the same four spellings country does — ISO-3, ISO-2, FIPS or an English name — and combine with AND, so source_actor_country=CHN&target_actor_country=USA,GBR,FRA is one call. Direction matters: over that same window the mirror question, the West acting on China, is a different 119 events.

Added — actor_country on its own, for the actor-origin half of country without the location half. Use it when an event that merely happened somewhere, with no actor from that country, is not what you meant.

Added — group_by=source_actor_country and group_by=target_actor_country on /api/v2/events/summary, so "China acted on whom, ranked" is one request rather than paging the list and tallying. Note the Stories summary deliberately does NOT gain these: a Story has no source or target actor of its own, only an undirected set of actor origins across its linked events, so offering them there would be a filter we could not honestly answer.

Added — meta.actor_filter, so what the filter could not judge is a number rather than a silence. About 12% of events carry no coded actor-origin country; under a directional filter those are neither in nor out, and a WHERE clause discards them without a trace. When you send an actor filter the response now reports evaluated, unevaluable and unevaluable_share for your window. The block is absent rather than zeroed when it could not be measured cheaply — an absent key means "not measured", which is a different claim from "nothing was dropped".

Fixed — an event whose two actors share the same name string could report the wrong target country. The snapshot pairs each actor with its country by matching the actor's name, which is right when the two names differ and ambiguous when they do not: the target then matched the source's entry first and inherited the source's country, or lost its own entirely. Found by comparing the two query paths over thirty days — fifteen rows in 14,420 on the target side. Corrected snapshots roll forward automatically on the next rebuild of each date; if you are reading history you may see a small number of target countries change, always toward the coded value.

Note on direction — on CAMEO+ events the source actor is the entity that performed the action. On conflict (ACLED) events the first actor is the PRIMARY actor and not necessarily the initiator, so source_actor_country there means involvement in that role rather than who started it. Worth knowing before building an escalation metric on it.

Fixed — subcategory on /api/v2/events matched nothing for every CAMEO+ code. GET /api/v2/events?category=ECONOMIC&subcategory=EC04 returned HTTP 200 with zero rows for a value the API itself declares valid, and applied_filters reported the filter as applied, so nothing in the response indicated a problem. The snapshot table stores subcategory as the display form 'EC04 · Trade Policy Action' while the request is validated down to the bare 'EC04', and the two were compared directly. It affected 100% of CAMEO+ events and none of the conflict family, whose values happen to be stored bare — which is why a Protests filter worked and every EC, TE, CR or POLITICAL code did not. The summary endpoint agreed with the list only by accident: it shares the same predicate, so subcategory with group_by=country returned zero buckets too. Both are fixed and now reconcile.

Changed — subcategory is now the code, and subcategory_label is the words. It used to serve 'EC04 · Trade Policy Action', which you could not send back: that exact string is rejected, and the code it contains returned nothing. A value you receive should be a value you can filter on, so the field now carries 'EC04' and the readable name moved to a new subcategory_label. If you display subcategory, read subcategory_label instead; if you match on it as a string, you now want the code. Query values are unaffected — label-style values are still accepted. Summary buckets keyed by subcategory changed the same way and gained a label, so a bucket you can see is now one you can fetch.

Fixed — event_description no longer appears on summary buckets that are not grouped by subcategory. It is carried through the aggregation to label CAMEO+ leaf codes, and was being published on every bucket of every grouping, so a POLITICAL bucket of 361 events reported the description of the single highest-significance event in it — reading as a property of the whole bucket.

Added — actors[].role is now documented, with the rule that governs it. The field separates who acted from who was acted upon, and it was published nowhere. Which pair appears is decided by family: CAMEO+ events are directed and carry source and target; conflict (ACLED) events are undirected — two parties to a clash — and carry actor1 and actor2. actor1/actor2 is not a legacy spelling of source/target, so a filter on actor direction cannot return conflict events. match_type and search_score are documented for the first time too: search_score is null off a search= request and also on a literal name match, because a name hit has no computed distance and inventing one would assert a similarity nobody measured.

Added — incident_resolution as a filter. Duplicate adjudication is partial by design (about 7% of events on a typical day), and the guidance to count incidents rather than rows therefore applied to a minority of any result set, with no way to select the rest. Pass incident_resolution=llm,self to get exactly the events where incident.uid is a trustworthy grouping key.

Added — include_total=true returns pagination.estimated_total, so a page can say '45 of 320' rather than only detecting that more exists. It is opt-in because it costs a second scan, and it is counted from the same filters and the same source as the page it accompanies. It returns null rather than a number on a search= request: semantic retrieval works from a bounded candidate pool, so any total there would describe the pool and not your query. Without it, pagination.next_cursor remains the truncation signal — non-null means more rows exist, null means the walk is finished.

Documented — goldstein_scale is null by definition outside two families, not sparsely covered. It is populated for CAMEO+ POLITICAL events and for every conflict event, and is null for the other nine CAMEO+ domains because the scale is not defined there. Measured on one production day that is 100%, 100% and 0% — about 42% overall, which reads like a coverage gap and is not. Worth knowing before you filter: a range filter on goldstein_scale excludes the null rows, so it narrows your results to those two families whether or not you intended it.

2026-08-15

Retired — confidence_profile no longer affects results on /api/v2/events, /api/v2/stories or either summary. It is still accepted, so nothing breaks, and any request that sends it now names it under applied_filters.retired with an explanation. It was never a filter on the confidence score its name suggests: any value other than loose required a story cluster to be graded primary and strong — internal pipeline grades we have never documented — which discarded roughly 61% of retrievable Stories. Worse, that grade is stamped once when a cluster is created and never revised, so a story graded weak in its first minutes and then covered by three hundred articles stayed excluded forever. If you were sending it, you will now see MORE results, not fewer, and those extra results were always real. Use confidence_min for a floor on the coder's per-event confidence score. Two side effects worth knowing: on /events the values balanced, precise and strictest were applying an identical cluster filter and differed only in that numeric floor; and an explicit confidence_min silently overrode the preset, so confidence_profile=strictest&confidence_min=0.1 applied 0.1.

Retired — min_confidence, a second spelling of confidence_min. Also still accepted and also reported under applied_filters.retired. Sitting beside confidence_profile it made three unrelated things look like one feature. Use confidence_min; its behaviour is unchanged. Note this is scoped to the events and stories endpoints — min_confidence remains a live, applied parameter on /api/v2/entities/{entity_id}/tone, where it means what it says.

Changed — the daily snapshots now serve a much wider history, and freshness is reported rather than guessed. Requests were previously refused from the snapshot path for any date older than fourteen days, regardless of whether that snapshot was current — so historical windows always paid the slower live query. A snapshot is now used whenever one exists and is complete, and meta.settled_at tells you when it was built. Measured over the last fourteen days, thirteen dates match the warehouse exactly and the largest difference is 0.43%.

Added — every event now says which real-world INCIDENT it belongs to. event_uid identifies a coded story, not an incident: when one event is covered by two story clusters, it is coded twice, so counting rows over-counts incidents and summing fatalities double-counts the dead. There was no field that let you tell. Each event record now carries an incident block with a uid you can group or count on instead of event_uid. Nothing is removed — the duplicate keeps its own event_uid and stays retrievable — so uniqExact(event_uid) is still the coded-story count and the incident uid is the incident count. Both are available; neither is imposed.

Added — incident.resolution, because coverage is partial and you should be able to see it. It reads unadjudicated (nothing ever compared this event to anything), self (compared and found unique) or llm (an independent adversarial judge confirmed a duplicate, and incident.uid names the surviving event of the group). The first two produce the same uid and mean opposite things, which is exactly why the field exists rather than being inferred. incident.confidence accompanies an llm verdict, and for a group of three or more it is the weakest link holding the group together, not the average. Only events that were candidates for a duplicate are ever adjudicated, so unadjudicated is the honest majority — on a typical day it is most rows.

Changed — history back to 2026-03-01 has been adjudicated. Earlier months turn out to be considerably more duplicated than recent ones: roughly 60% of examined March conflict pairs were confirmed duplicates against 15-30% in August, and many are byte-identical — the same arrest, the same strike, the same roadside attack, coded twice from two clusters on the same day. If you have built totals over the spring you may find them meaningfully lower once collapsed on the incident key. The survivor of a group is its earliest-dated member, chosen so the key does not move between two identical requests.

2026-08-14

Fixed — country_iso3 returned every event, everywhere. The events and stories lists read only the `country` spelling, while the response echoes the resolved set back to you under `country_iso3` — so replaying that value, which is the natural thing to do and what an agent does automatically, returned the entire unfiltered window with a 200 rather than the country you asked for. A country-scoped screen read as though there were no matches anywhere. Both spellings now resolve identically, as they already did on filings, maritime and the screening lists. If you have been filtering with country_iso3, your results change: they were previously not filtered at all.

Fixed — story URLs on event records could contain mangled characters. The link an event carries to its story was built from the raw cluster label rather than the cleaned one, so a story about the río Iguazú produced /stories/cataratas-el-rxedo-iguazxfa-… The story page itself always used the cleaned form, so the two disagreed. Affects roughly one link in 150, concentrated in non-English coverage. Old links continue to resolve — a story URL is matched on the identifier at the end, not on the words.

Added — every /api/v2/events response now carries a meta block. meta.row_source says where the rows came from: live, meaning computed from the warehouse at request time, or settled, meaning read from a pre-built daily snapshot. meta.settled_at gives the build time of that snapshot — the oldest one in the window you asked for, so it understates rather than overstates — and is null on the live path, which has no snapshot to date. meta.row_source_reason is one of three values: settled, not_settled, or filter_not_supported, the last meaning a filter you sent cannot be answered from a snapshot so the request was computed live. Today every response reads live; the snapshot path is built but not yet switched on, and this note will be updated when it is. Nothing about the rows changes either way — the two paths return the same events, in the same order, with the same fields.

Changed — event records now carry their article count and language breakdown in the daily snapshots, matching what the live path computes. Those two fields were previously only ever computed live, so a snapshot-backed read would have reported an article count of zero and an empty language list.

Fixed — an actor could be duplicated across both slots of an event. Where an event had a target actor and no source, the stored record put that same actor in both offices, so a record with one participant read as two, and its generated title named the actor against itself. This affected the stored daily snapshots only, never the live API, and the affected records are being rewritten.

Added — a plugin for Claude Code and Codex, and a /build page that installs it. One command wires both the data MCP server and the documentation MCP server into your agent, along with five workflow skills: a Core-API primer plus war-risk underwriting, counterparty exposure, supplier disruption, and country risk as a joinable time series. The marketplace is public at github.com/gdelt-cloud/plugins. A documentation-only plugin is available with no account at all, if you just want your agent reading the reference while it writes your code.

Fixed — the documentation MCP URL was linked as if it were a page. docs.gdeltcloud.com/mcp is a JSON-RPC endpoint, so opening it in a browser returns a 405 error blob; it was linked that way from the homepage, the app sidebar, the public mobile nav and the Connect page. The MCP documentation now lives at /mcp/overview and the endpoint is only ever offered as something to paste into a client. Two pages of the documentation, /mcp/integrations and /mcp/skills, were also infinite redirect loops, and /reference/core-articles returned 404 while sitting in the navigation. All are live again.

Fixed — the Connect page's code samples pointed at a hostname that does not resolve. Every cURL, Python and TypeScript snippet on that page used api.gdelt.cloud, which has no DNS record, so a copied snippet failed before it reached us. The base URL is gdeltcloud.com/api/v2, as the OpenAPI spec has always said.

Changed — the summary endpoints now document the filters they actually accept. /api/v2/events/summary and /api/v2/stories/summary honour days, date, entity, country_match, geo_precision and the observed_* window, and the published spec declared none of them — so the endpoint index, which is generated from that spec, listed all of them as unavailable. They are documented now. The handful genuinely not accepted is short and the endpoint says so itself: near, lat, lon and radius_km come back under applied_filters.ignored, and search is refused with a 400. Nothing about the API changed; the description of it did.

Fixed — bounding boxes have two axis orders and the error reference documented only one. Events, stories, facilities and energy take latitude first; the maritime endpoints take longitude first. For most real boxes both orderings are numerically valid, so a swapped box cannot return an error — it silently queries a different part of the planet. The INVALID_BBOX guidance now names both families and says which endpoints each applies to.

Changed — five pages said list endpoints default to the last 24 hours. Event and story lists default to seven days; other families carry their own default. The parameter reference now carries an identifier table showing, for every endpoint that takes an entity, what that endpoint says it accepts — because a spine id, a news id, a GEM id, a CIK and an LEI are not interchangeable, and sending the wrong one returns an empty result rather than an error.

2026-08-13

Fixed — an entity-scoped event summary returned global totals. GET /api/v2/events/summary with an entity filter and the default grouping ignored the filter entirely and reported counts for the whole corpus: 14,296 events over one week where the correct answer was 104. The list endpoint and the same summary grouped by country were always right, so the two disagreed by a factor of 137. If you built a volume-over-time chart on the default summary call for a single entity, re-run it — the numbers have changed.

Added — country_match, so you can ask for events located in a country rather than events connected to it. country= has always matched a country either by where the event happened or by the origin of an actor involved, which on a typical day means about one in seven results for a country query happened somewhere else. That behaviour is unchanged and remains the default. Passing country_match=location restricts to geography alone. It works on events, stories and both summary endpoints, and the parameter reference now states the default semantics plainly.

Changed — the daily serving tables now refill gaps in both directions. A date that had never been settled could sit empty indefinitely while the hourly job kept refreshing the current day; two days of events were affected. Backfilling now takes priority over refreshing, so an empty day is filled before a complete one is updated.

2026-08-11

Changed — the documentation is smaller and the reference is now generated end to end. docs.gdeltcloud.com went from 73 pages to 31. What went is duplication, not information: a taxonomy page restating 451 lines of codes, categories, regions and languages that the generated reference already published, a concepts page whose response schemas were already in the OpenAPI spec, and per-dataset pages whose value tables now link to the value reference instead. Every published value — every enum, code, parameter, formula and licence — is emitted from the same objects the server imports at request time, so a documented value is one the API actually accepts. A test now fails the build if a hand-written page restates one.

Added — two task-shaped guides. "Build a monitoring feed" walks the pattern the API is designed around: resolve a name to an entity id once with GET /api/v2/search, then reuse that id across events, stories, government awards, facilities and ownership exposure. "Answer a question with MCP" does the same work through a connected model, and both show the REST and MCP forms side by side. The quickstart is one screen and now opens with an unfiltered call rather than a five-filter example against a fixed date window.

Added — a data catalog at /data/catalog stating which datasets we produce and which are open feeds we ingest, with the source, licence, coverage window, refresh cadence and known limitations of each. It is generated from the same records that back the public data page, so the two cannot disagree.

Changed — the API reference sidebar is now ordered Core, then Open Feeds, then Intel, and is generated from the specification rather than maintained by hand. All 75 operations and their URLs are unchanged.

Changed — every parameter that takes a fixed or measured set of values now links directly to that value list in the reference, on all 101 of them. Deprecated parameters (event_family and domain, both superseded by category) moved out of the main parameter tables into a section of their own naming the replacement. They continue to work exactly as before.

Changed — the v1 API documentation has been retired. The v1 endpoints continue to serve existing integrations unchanged; they are simply no longer documented, and their pages redirect to the v2 reference. New work should use v2.

2026-08-10

Fixed — exposure list filter returned a confident empty result. GET /api/v2/exposure accepted any string for list (and its alias source) without checking it, so an unrecognised value returned 200 with zero rows and no warning. On a sanctions surface that is the worst possible failure: an empty result reads as "this asset is not on that list" when the truth was "we did not understand your filter". Two lists our own exposure page offered in its picker, UFLPA and the EU consolidated financial sanctions list, are declared but not yet ingested and carry no rows at all, so selecting either produced exactly that false negative. An unrecognised value now returns 400 with the accepted values, and a list we declare but do not yet carry returns 400 with details.reason set to declared_but_not_ingested and a message saying so explicitly — never an empty success. The picker no longer offers a list we cannot answer for; both it and the API Arena now derive their options from the same registry the server validates against, so they cannot drift apart again.

Fixed — filtering exposure by a China list returned nothing. Under lens=china the exposure rollups record a list membership internally as list_<name>, so filtering the same data with list=csl_ofac_cmic matched none of it — 121 exposed assets for OFAC CMIC and 111 for DoD 1260H were unreachable through the filter, while the identical filter worked under lens=sanctions. Both spellings are now accepted on every lens, so one value works throughout, including the prefixed form if you send back what a response gave you. The two signals that are not lists, state_owned and cn_state, remain valid filter values and are now documented as such. Matching is also case-insensitive across the screening and exposure endpoints.

Changed — one error code for an invalid screening list. Rejecting a list value used to return either INVALID_LIST_SOURCE or LIST_SOURCE_NOT_AVAILABLE depending on why. Both now return INVALID_LIST_SOURCE, and the distinction moved into details.reason as declared_but_not_ingested or unknown_source_key, which is structured rather than something to infer from a code. The message is unchanged and still says plainly when we do not carry a list, so no information is lost. If you branch on the error code, branch on details.reason instead.

Fixed — maritime activity time bucket. GET /api/v2/maritime/activity documented bucket=hour|day but did not enforce it: any other value was silently replaced by the automatic grain and echoed back as the one we chose, so bucket=week returned daily rows labelled bucket: "day". An unrecognised value now returns 400 with the accepted values, matching every other filter on the surface. Omitting bucket is unchanged and still means automatic — hourly for spans of two days or less, daily beyond — and the response continues to report which grain was used.

Fixed — entity tone. Our API reference listed a bucket parameter on GET /api/v2/entities/{entity_id}/tone with values day, week and month. No such parameter exists and none of them ever did anything: entity tone is scored per entity per story per day, every row carries bucket_granularity: "day", and bucket=month simply returned daily rows with a 200. The parameter has been removed from the specification rather than left as a request that looks honoured and is not. If you were sending it, nothing about your results changes; aggregate on your side, or narrow the window with date_start and date_end.

Fixed — Atlas GPR component. The specification declared component as a flat five-value list, but which components exist depends on which lens you ask for: the events lens carries all five, the GPR lens has no verbal or material split, and the attention lens is a single undecomposed series. Six of the fifteen combinations the flat list implied cannot return a row, and the server was already rejecting them — so the document was promising requests that could not succeed. The dependency is now published: the reference shows the legal set per variant, the specification states it, and the 400 returns that variant's set in details.accepted_values. Server behaviour is unchanged.

Changed — source languages. The languages filter is documented as a measurement rather than a fixed list. Two hand-maintained lists of "62 recognized source languages" existed — one in the docs, one behind the filter UI — and they were different 62s: they agreed on 50 and each carried a dozen the other did not. Neither matched our corpus. Sixteen languages we actually publish could not be selected in the filter at all, including Croatian, Urdu, Tamil, Telugu, Malayalam, Marathi, Punjabi, Kannada, Gujarati, Sinhala, Catalan and Malay, and three codes were advertised with no coverage. Both lists are replaced by a single generated reference showing every language with measured coverage — 77 over the last 30 days — refreshed from the warehouse and dated. Validation is unchanged: we reject only what cannot be an ISO code, so a valid code we have not seen yet is still accepted.

Known issue — three language codes are not what you would expect. Azerbaijani coverage is stored under axe rather than az, Galician under glg rather than gl, and some Mongolian under mon rather than mn, because those are the spellings our upstream feed uses and we do not currently fold them. The practical effect is that languages=az returns nothing while Azerbaijani coverage exists, and Mongolian is split across two codes. Until we fold them and reprocess the affected rows together, filter on the spelling shown in the value reference. Coverage from our own directly-ingested sources is unaffected.

2026-08-08

Changed — event coding routing. The router that decides which coding pipeline a story goes to can now also move a story out of the conflict pipeline and into a CAMEO+ domain. Previously the correction only ran the other way, so a story the first-pass rule sent to conflict stayed there. That rule is a fixed lookup on the story's category, decided before any model reads the text, and on a 432-story labelled sample it picks the wrong pipeline about 37% of the time; letting the correction run in both directions takes that to about 29%. To be plain about what this is and is not: the accuracy of the resulting coded events is unchanged. Measured paired across 4,311 coding runs, exact agreement with the labels went from 39.1% to 39.4%, which is not a real difference, and we are not claiming one. The pipeline was already recovering most wrong-pipeline stories on its own — the coder refuses when the story does not fit the book it was handed, and the story is then re-coded in the right one — so routing correctly the first time mostly removes a second pass rather than changing the answer. The benefit is cost and latency: re-codes fell 32% and total model spend on the same corpus fell 10.6%. Nothing is added to or dropped from the event set; refusals and empty results were flat. What can differ is which taxonomy a given story is coded in, so an event that would previously have been recorded as a conflict event may now be a CAMEO+ event with a domain and root code, or the reverse.

Changed — event coding methodology. The top-level router, the first step that decides which coding pipeline a story goes to and proposes its CAMEO+ root, now runs on a higher model tier. Routing is a judgment over unstructured text rather than a classification, and the smaller model was not stable at it: asked the same question twice, it gave the same answer on 52.5% of stories, against 74.0% for the new model, measured paired over 200 production stories. Carried through to the final coded event, agreement rose from 57.5% to 69.0%. The practical effect is that fewer stories are sent down the wrong pipeline, and the event type and CAMEO+ code attached to a story are more likely to be right and more likely to be reproducible. The previous router proposed a root code on 26.8% of stories and was correct on 28% of those; the new one proposes one on about 71%. Coded events are otherwise unchanged in shape — same fields, same taxonomy, same endpoints. Only the classification a story receives can differ, and we expect the difference to be an improvement. We also tested giving the router full article text instead of headlines and it made routing worse, so the router continues to read headlines.

Fixed — events. GET /api/v2/events and GET /api/v2/events/{id} could name different stories for the same event. When an event's story sits on a different calendar day from the event itself — about 13% of events, from cross-day coding and the prior-day ingest window — the list endpoint could not see that story and fell back to a stale pointer, often one that had since been merged away and held no articles. The by-id endpoint resolved it correctly, so the same event returned one story when listed and another when fetched. On a sample of 40 cross-day events, the two endpoints disagreed on 5; they now agree on all 40. This affects story_refs, primary_story_url and metrics.article_count on the list endpoint, and the same fields wherever events are summarised. No event was added to or removed from any result — only the story an event points at changes.

Fixed — events by id. GET /api/v2/events/{id} returned 404 for an event whose story sits more than two days from its event date, while the same event appeared normally in GET /api/v2/events. Those ids now resolve.

2026-08-07

Added — 75 official CAMEO event codes that our taxonomy had never carried. The POLITICAL taxonomy went from 164 leaf codes to 240, and now contains every code the CAMEO codebook defines under roots 01 through 13 and 15 through 17. The gaps were whole branches, not stragglers: every root's official "not specified below" residual (020, 030, 040, 050, 060, 070, 080, 090, 100, 110, 120, 130, 160, 170), and eleven complete four-digit sub-trees — intent to provide aid (0331-0334), intent to reform (0341-0344), intent to yield (0351-0356), acceding to reform demands (0831-0834), releasing persons versus property (0841, 0842), receiving peacekeepers, inspectors and humanitarian access (0861-0863), demanding material cooperation (1011-1014), demanding aid (1031-1034), demanding that a target yield (1051-1056), rejecting cooperation (1211-1214), rejecting aid requests (1221-1224), rejecting reform (1231-1234), refusing to yield (1242, 1244, 1245, 1246) and reducing aid by type (1621-1623). Also added are the two codes CAMEO introduced in its 2012 revision and we had never picked up: 155, mobilize or increase cyber-forces, and 176, attack cybernetically. Three further singleton appeals were missing and are now present: 0234, 0252 and 0255.

What this means if you call the API. Every one of these is now a valid subcategory filter value on /api/v2/events — previously they returned 400, because we only accepted codes we ourselves could emit. Nothing that worked before has changed. Note that these codes are newly emittable, so they carry no history: an event whose text would today be coded 1056 (demand de-escalation) was, before today, coded at its parent 105. When you query a newly added child code, read a low count as "new", and query the parent alongside it if you need the full historical series. Coverage of the parents themselves is unaffected.

Two things deliberately stay out. Codes 173 (arrest or detain) and 175 (violent repression), and the whole of CAMEO roots 14, 18, 19 and 20 (protest, assault, fight, mass violence), remain absent from this taxonomy because those events are coded by our ACLED pipeline instead; carrying them here would double-code the same event under two families. That exclusion is now the only difference between our POLITICAL taxonomy and the official CAMEO code list. Separately, the new residual codes mean the same thing as the bare two-digit root they sit under — 020 and 02 are the same answer — so our coder continues to prefer the root, and we recommend querying the root if you want both.

Fixed — event taxonomy labels. Eight more POLITICAL labels named a narrower thing than the CAMEO code they sit on, which told both our coder and anyone reading the taxonomy to rule out cases the code exists to catch. Code 101 was "Demand information/investigation" and is now "Demand material cooperation" — official 101 covers any demanded material exchange, economic or military as much as judicial. Code 103 was "Demand aid/protection" and is now "Demand material aid". Code 1044 was "Regime change" and is now "Institutional/regime change", which reaches any change to the rules of the game, down to amending an electoral law. Code 1385 was "Threaten attack with WMD", a name CAMEO retired in 2012; it is now "Threaten unconventional mass violence", meaning weapons of mass destruction but equally a threatened mass expulsion, mass killing or ethnic cleansing with no weapon mentioned. Codes 1661, 1662 and 1663 were "Expel peacekeepers", "Expel inspectors" and "Expel aid agencies" and are now "Expel or withdraw …" — the official codes are symmetric and cover a voluntary pull-out by the provider exactly as they cover an expulsion by the host. And root 17 was "COERCE (non-violent)" and is now "COERCE": CAMEO does not scope that root to non-violent acts, and seizing, confiscating or destroying property (171, 1711, 1712) is officially a use of force and has always been carried under it. If you display our subcategory names or match on them as strings, these eight will read differently from today.

As with the code corrections below, the numeric codes have not changed — only the labels attached to them. The direction of the error matters for anyone querying history: because each old label was narrower than its code rather than pointing at a different one, events coded before today should be read as under-covered on these codes rather than mislabelled. Over the last 30 days the eight carried 478 events, nearly all of them on 101 and on the bare root 17; codes 1385, 1661, 1662 and 1663 carried none at all.

Fixed — event taxonomy. Four CAMEO codes in the DEMAND family carried the wrong labels. Codes 105, 107 and 108 were rotated against the official CAMEO codebook: 105 was labelled "Demand mediation" when it means demand that the target yield, 107 was labelled "Demand ceasefire" when it means demand settling of a dispute, and 108 was labelled "Demand meeting/negotiation" when it means demand mediation. Code 106, demand meeting/negotiation, was missing from our taxonomy entirely and has been added. Code 1241 was labelled "Refuse to ease sanctions" without qualification; official 1241 covers administrative sanctions only, so economic-sanctions cases were being pulled into it. The numeric codes themselves were always correct and have not changed — only the meanings attached to them. Events coded before today carry the old meanings: in the last 30 days that is 73 events across codes 105, 107, 108 and 1241. If you filter on those four codes, treat records created before 2026-08-07 as carrying the previous interpretation.

Fixed — quad class on investigation events. Events under CAMEO root 09 (INVESTIGATE) were being classified as "Verbal Cooperation". By the standard four-way aggregation, roots 09 through 13 are Verbal Conflict — and our own Goldstein anchor for root 09 is negative, which cannot sit in a cooperation class. Root 09 is now classified as Verbal Conflict. This affected 598 of 619 investigation events in the last 30 days, roughly 3 percent of all political events in that window. Historical events retain the quad class they were coded with and were not backfilled; the goldstein_scale field on these events was always correct and is unaffected.

2026-08-05

Changed — plans. Every tier, including Free, can now call every source dataset we have: events, stories and entities, the fused facilities directory, GEM energy and heavy-industry assets, media tone and Share of Voice, government awards and FARA, SEC filings, Epoch AI, macro, screening lists, GLEIF and maritime. Plans differ on volume rather than on which data you can reach. Free stays a trial rather than a production tier — 100 query units a month is well under the roughly 750 it takes to keep a single entity current — and Monitoring Briefs, Atlas indices, the entity dossier and point-in-time history remain on the paid tiers. If you previously received a 403 on energy or facilities, those calls now work.

Fixed — screening. Passing an entity id to /api/v2/screening/match returned no matches for entities that are in fact sanctioned, because the id form the endpoint itself returns was not one it could look up. A screen by id now resolves through the same entity linkage the lists endpoints use, so a listed counterparty matches. An id we cannot resolve at all now returns a 400 that says so, rather than an empty result that reads as a clean screen. Separately, raising the match threshold could previously increase the number of matches and return scores below the threshold you set; an explicit threshold is now a real floor on what comes back.

Fixed — government awards. Combining filters on /api/v2/gov/awards widened the result instead of narrowing it: an entity filter plus a recipient filter returned the union of both, so the headline obligated-dollar figure could be the sum of two unrelated companies. Filters are now combined as expected. Totals returned for a single filter were always correct.

Fixed — request validation. An unrecognised language code (for example languages=english rather than languages=en) returned an empty result while the response asserted the filters had been understood; it now returns 400 with the accepted format. A malformed CIK on /api/v2/filings/events silently returned every filer's events instead of an error. An out-of-range offset or cursor returned a 500 on several endpoints, including /api/v2/events; it now returns an empty page.

2026-08-04

Fixed — reliability. Two hourly windows on 2026-08-04 (09:00 and 10:00 UTC) produced almost no coded events, and the same failure had been quietly costing roughly one hour of event coding every twenty-eight hours for several weeks. The cause was not the coding step itself: after each hour's editorial review, the pipeline cleans up superseded records across seven tables, and it was doing so in batches of a hundred identifiers — around seventeen separate blocking cleanup operations per hour against the analytical store, each one rewriting data on disk. That cleanup had grown into the single largest cost of the hourly run, larger than the event coding it follows, and on busy news hours it pushed the run past its execution limit, which discards that hour's coding entirely. The cleanup now runs in far fewer, larger operations covering the same records. Articles, clustering, and the underlying stories were never affected — those are written before coding begins — and the hourly catch-up pass recovers coded events for affected windows.

Improved — the hourly pipeline now records when each half of the run begins and ends, so a run that is killed by its execution limit is visible as a failure rather than as an absence. Previously such a run left no error of any kind, which is why the recurrence above went unnoticed. This is internal instrumentation and does not change any API response.

2026-08-03

Fixed — reliability. The entity-tone scoring queue had been accumulating rows that could never be worked: 9.8 million of the table's 10.7 million rows were stale queue entries for work that was already complete. Reading that queue scanned nearly 13 million rows every fifteen minutes and twice pushed the analytical cluster to its memory ceiling, which is what took the API offline briefly on 2026-08-02 and again on 2026-08-03. The queue now retires entries as soon as their work is done, carries a retention bound, and has been cleaned up — the table went from 10.7 million rows to 860 thousand. No tone data was affected: every scored result is untouched, and the historical tone record is complete.

2026-08-02

Fixed — an empty result from GET /api/v2/events and GET /api/v2/stories now says what it means. These endpoints returned a bare success response with an empty array, which is indistinguishable from a rejected filter value or a broken endpoint, so a caller sweeping many filter combinations had no way to tell a genuine coverage gap from a mistake on their side. Empty responses now carry a note stating that empty means no coverage for that combination and not zero real-world activity, listing the narrowing filters that were applied in order of how much each one restricts the result, and pointing at the corresponding summary endpoint. Invalid values still return 400 with the accepted set, so a 200 with an empty array now unambiguously means the filters were understood and nothing matched. Nothing else about the response shape changed, and the note is absent when rows are returned. Worth knowing when planning a sweep: conflict categories are genuinely sparse per country — over a representative 23-day window there were 280 non-empty country-and-category combinations out of roughly 1,170 possible, and category=Battles had coverage in 18 countries.

Fixed — Atlas GPR could serve a stale reading for a day indefinitely. Each daily observation is stamped with the date it first became knowable, and the serve layer shows whichever stamp is latest. A restatement run against a day that was still in progress captured a few hours of coding and stamped it with a date in the future, so that partial snapshot outranked the correct, complete measurement computed the following day — permanently, because no later run could ever produce a higher stamp. For 2026-08-01 the world reading was computed over 122 events when the day actually held 1,272. Vintages are now clamped so one can never be dated in the future, restating a day that is still in progress is refused outright, and any day whose served value is being outranked is reported. Previously affected days are being restated.

Fixed — the Atlas panel no longer states a conclusion it cannot support. When a series has too little history to place a reading on its band ladder, the band is deliberately withheld; the summary sentence was treating that withheld state as an ordinary value and asserting the place was holding near normal, including while the index read 0.63x normal. It now says the reading is shown and the interpretation withheld. The same sentence also named a leading child region drawn from whichever day each region last had sufficient coverage, which could be a different date from the one on screen; a leader is now only named when its reading is for the displayed day.

Fixed — reliability. A single cluster whose embedding could not be recovered would abort an entire hourly ingest run, because the story table's vector index requires every value to be the same length and rejects the whole batch otherwise. This cost several hours of event coding between 2026-07-29 and 2026-08-01, visible as gaps in the hourly volume on the Data Status page. An unusable embedding now costs that one cluster and is reported, never the hour. Separately, a query that fails because the analytical cluster is out of memory is no longer retried — retrying asks the exhausted resource for more of itself, and that amplification turned a brief capacity event into an extended one. Deliberate back-pressure from our own concurrency limiter is unaffected and still retries.

2026-08-01

Fixed — a badly fragmented Story could never be consolidated, no matter how many merges our adjudicator approved. Duplicate Stories are merged by taking the transitive closure of accepted merge pairs, then requiring that a component carry no more than two pairs no adjudicator ever examined. That guard is right — an implied weld nobody checked is false about half the time — but it was enforced by discarding the entire component. Candidate generation supplies at most 3n/2 examined pairs for a component of n clusters while the check demands roughly n(n-1)/2, and those cross just under five, so any group of five or more fragments was mathematically unmergeable. Measured on 2026-07-31: two-fragment groups merged 481 of 481, groups of six or more merged 0 of 62. One migration story held 132 fragments with 750 already-approved merges, every one discarded, leaving 111 duplicate Stories live.

Merges are now applied one pair at a time in ascending distance order, and only the pair that would breach the limit is refused — the rest of the group still merges. Every resulting Story still satisfies the identical two-unexamined-pair guarantee, so this is not a partial merge of a suspect group; each one independently passes the same test. Replaying five days of real verdicts on the hourly schedule the pipeline actually runs (the harness reproduces 91-98% of production's real merge counts): 8% to 24% more duplicates consolidated per day, and the migration story falls from 111 live Stories to 26.

Duplicate detection now probes each Story against the day's others individually instead of computing every pair in one query. The old approach grew with the day and stopped finishing around 8,500 Stories, which meant the last six hourly passes of every UTC day failed and merged nothing — and because a day is never revisited, the entire evening news cycle stayed un-deduplicated permanently. The new path is 9.6x faster at exactly that size, finds no fewer duplicates (verified against every merge verdict from a full day), and surfaces roughly 53 more real duplicates per pass that the previous method could not propose at all.

Fixed — a Story pair we had explicitly judged to be DIFFERENT incidents could still be merged. The safety check counted any examined pair as satisfying it, so a "no" was treated exactly like a "yes" — and because the exhaustive sweep over the day's biggest Stories compares every pair among them and roughly 95% come back rejected, the more carefully a group had been examined and refused, the more freely it could be welded together. Over 2026-07-27..07-31 that merged 494 pairs we had explicitly rejected, including one 24-cluster Story joining US and Saudi strikes on Iraqi militia facilities to a separate US strike on Iran's Qeshm Island. A rejected pair now blocks those two Stories from ever sharing a merge group, and the count is zero on every day tested. Separately, rate-limit and transport failures were being stored as "different incident" verdicts — 11.2% of one day's rejections were HTTP 429s — which both suppressed the pair from ever being judged and fed this same defect; they are now retried instead of recorded.

Known limit — this fixes what happens to merges we approved, not how many pairs we look at. A Story fragmented across hundreds of clusters still has most of its pairs never compared, because candidate generation ranks each cluster's three nearest neighbours and the hourly pass that would widen that has been failing in the evening since 2026-07-27. Expect fewer duplicates, not none, until that lands. If you deduplicate Stories yourself, note that merged Stories continue to be marked superseded rather than deleted, and the counts on surviving Stories will move upward.

2026-07-31

New — a second Atlas GPR construction, served in parallel as construction=world_corpus. It is the construction the field's reference index actually uses: a place's share of the WORLD's coded events over a 14-day window, normalized to that place's own frozen normal. The default construction, construction=own_coverage, divides by the place's own coverage, which is topic volume rather than corpus size — and that let the index move opposite to its own events, as on 2026-07-16 when Ukraine's qualifying events went from 8 to 15 while the published index printed its monthly low. Fourteen days is two whole weeks, so each weekday appears exactly twice and the corpus's weekday cycle cancels by construction: measured day-of-week amplitude falls from 35.0% to 3.7%. No severity weighting, because it does not survive testing — the Fed's own intensity-weighted variant correlates 0.97 with plain counts, and fatalities exist on only 28% of qualifying events, so weighting by them would flatten the entire threats half of the index by schema accident. The default is unchanged. We named these by their denominator rather than v1/v2 on purpose: the endpoint already lives under /api/v2, so a version-shaped value would have read as which API rather than which index.

world_corpus enforces a coverage floor on the base window, not just on the day: a series needs 100 qualifying events behind its reference distribution or the reading is withheld. Without it the construction is unusable where data is thin — Burkina Faso, with one event in its base window, medians an index of 1,166, and 31 of 109 geographies are persistently mis-levelled. Above the floor the median is 91 and nothing falls outside 50 to 200. Coverage is published as precision rather than folded into the index: every response carries days_in_window and base_events whether or not the reading clears. A world_corpus reading is a trailing 14-day state, so the series peaks in the days FOLLOWING a burst of events — never read a peak date as the date something happened.

Changed — the deviation baseline is now frozen over a fixed window instead of recomputed over the trailing 90 days each week. A rolling baseline re-anchors a country to its own recent past, so a country at war for the whole window gets a wartime normal and its index decays toward 100 at the peak of exactly what the index exists to detect. Both GPR and EPU anchor permanently. Each re-freeze mints a new baseline_version and retires the previous one; nothing is overwritten.

Fixed — every reading is now normalized against the baseline built from its own coder generation. The event coder changed on 2026-07-15, and the two generations disagree sharply: across 940 country series the newer anchor differs from the older by more than 25% on 638 of them. The serve layer had been picking one baseline per series with no coder condition, so which one you got was an arbitrary database tie-break — and normalizing a new-coder reading against the old-coder norm moves the published index by up to two or three times. Responses now carry baseline_coder_version. A series spanning a coder change is not one comparable series, and we would rather say so than quietly splice it.

Fixed — asking GET /api/v2/intelligence/gpr for a decomposition a lens does not publish now returns 400 with the components that lens actually has, instead of an empty 200. Components are per-lens: the Attention lens is a single undecomposed series, and the GPR lens has no Verbal or Material split. Six of the fifteen lens-and-component combinations the API Arena offered could never have returned a row. The Arena picker now derives its options from the same registry the server validates against, so the two cannot drift apart.

Fixed — Atlas readings now withhold the band, not just the value, where the reference distribution cannot support one. A band is a promise about how often a reading is unusual — roughly a tenth of a place's days sit above the ninth decile — and that promise needs a distribution with spread in it. On 160 of 206 country series the frozen cut-points are either collapsed (every cut-point equal, so any non-zero reading printed as Extreme) or unreachable (the top band would require 100% of a place's coverage to be tension-bearing). Those series now return band: null with band_status: 'degenerate_baseline'. The reading itself is unchanged, and the baseline block now carries n_obs and bands_usable so you can see which case you are in.

Fixed — source_mix returns null with status: 'not_measured' instead of zeros. The distinct-outlet and new-source diagnostics are not computed yet; the columns behind them are non-nullable, so the compute pass writes 0 as a storage placeholder. Serving that 0 read as a measurement of zero sources. It becomes a real number when the diagnostics pass lands, and the response shape will not change.

Fixed — GET /api/v2/intelligence/posture compared a GDP-weighted current window against an attention-weighted prior one, so the trend differenced two estimators rather than two periods and could flip its own direction word. Both windows are now measured on the requested weighting. The trend object also states its basis: the delta describes the dynamic axis, while the published score blends that with an annual structural axis that is frozen within any window Posture serves — so a new headline_delta_equivalent gives what the headline actually moved.

2026-07-29

Fixed — Event article counts. An Event carried the article count of its Story as it was when the Event was coded, and that snapshot was never revised as the Story kept accreting coverage. So /api/v2/events/{id} and /api/v2/events/{id}/stories could report different counts for the same Story, and 26.3% of Events over a 7-day window disagreed with the live Story (1,604 of them under-counting). Both now read the live count, so metrics.article_count and story_refs[].article_count agree with /api/v2/stories. If you have cached Event article counts, expect them to move — upward in most cases.

Fixed — an Event's Story pointer could name a Story it was no longer linked to. When a Story is re-homed between two live Stories, the Event's stored pointer was left behind, so the Event card named one Story while /events/{id}/stories named another. 17.6% of Events disagreed with their live link; 7.6% pointed at a Story that was still live, which is why the existing repair (which only fired on merged-away Stories) never caught them. The link table is now authoritative whenever it contradicts the stored pointer.

New — event_code is now null rather than an internal id. When an Event has no CAMEO+ code, event_code previously fell back to an internal identifier that looked like a code but was not one. This affected every conflict-family Event, which has no CAMEO+ code by construction. It is now null. The Event id is unchanged and still available as id.

New — taxonomy_status on the Event card. A small share of Events (4.2–8.5% per day) are coded but are missing their taxonomy record, so category, subcategory, event_code and the sub-factor metrics are all null for a data-integrity reason rather than because the Event is genuinely sparse. taxonomy_status is 'coded' or 'detail_missing' so you can filter for fully-coded Events instead of inferring it. The underlying cause — a re-review step that could strip taxonomy from an Event it was not re-coding — is fixed going forward.

New — Event metric evidence is now served and shown. metrics.metric_inputs returns the observables the coder read off an Event (magnitude path, systemic size/interconnectedness/irreplaceability, propagation channel/coupling/breach/primed/containment, market claim-exposure/economic-bite) with the coder's recorded reason for each value, plus metrics.metric_version identifying the formula contract. Event pages render these next to each score with the published formula, so a score can be re-derived by hand. Present only on Events coded under the current contract; the key is omitted entirely otherwise, never zero-filled.

Fixed — /api/v2/stories/summary now honours the entity scope. entity, entity_id and entities were accepted and silently ignored on this endpoint, so an entity-scoped request returned the global corpus: an entity holding 2 Stories reported 69,358 over 7 days. The scope now applies on every group_by, is echoed in applied_filters.entity, and an unresolvable entity returns no rows with an explanatory note rather than falling back to global totals. /api/v2/events, /stories and /events/summary were already correct.

Entity pages now read the same endpoints you do. Linked Stories, the Event timeline and the Event map are served by /api/v2/stories?entity= and /api/v2/events?entity= instead of page-specific queries, so the labels match the API exactly — an Event subcategory reads '010 · Make statement (other)' on the page as it does in the response. The 30-day activity pulse is backed by /api/v2/stories/summary?group_by=date.

Terms: the Accounts and access section now states explicitly what the free plan is for and what it is not. Free accounts are for individual evaluation and non-production use, one per person and one per organization, and you may not spread usage across multiple accounts — including accounts on different email addresses, domains, or affiliated entities — to obtain extra free quota or avoid fees that would apply if the usage were combined.

Where accounts belong to or are operated for the same organization, we may treat their usage as a single account for plan limits and billing, and ask you to consolidate onto a paid plan. Accounts that keep circumventing plan limits after we have raised it, and after a reasonable opportunity to move to a suitable plan, may be rate-limited, suspended, or closed.

This is a clarification of the existing Acceptable use rule against bypassing limits rather than a new restriction, and it is not applied retroactively. If you are a team currently running on several free accounts, a single organization plan pools one quota across every member and gives you per-member and per-endpoint visibility that separate accounts cannot — email hello@gdeltcloud.com and we will help you consolidate.

2026-07-28

New: the GLEIF Global LEI Index is now an Open Feed at /api/v2/gleif/entities, /entities/{lei}, /relationships and /isin — 3.39M legal entities with their registered name, jurisdiction, entity and registration status, and LEI↔ISIN mappings. Published by GLEIF under CC0 and served close to as-published. Available on Analyst and above. Because the feed covers 3.39M records, an unfiltered listing is refused with 400 FILTER_REQUIRED rather than served slowly — pass at least one of lei, name, country, jurisdiction, entity_status, registration_status or entity_category.

New: /api/v2/entities/{entity_id}/hierarchy returns an entity's corporate hierarchy — direct parent, ultimate parent and children. It accepts the same identifiers as the rest of the API (a name, an e_ id, a wikipedia_url) and additionally a bare 20-character LEI, so the id you searched with works at this hop too. Gated on the existing exposure entitlement; the LEI itself stays ungated.

Read the hierarchy as what it is: accounting consolidation as reported to the Global LEI System under IFRS/US-GAAP. It carries no ownership percentages and excludes natural persons, so it is not beneficial-ownership data. Coverage is partial by design — a filer may declare a reporting exception instead of naming a parent, and the response says which: coverage.reporting_exception distinguishes a declared absence from an unknown one, and an entity with no LEI in our crosswalk returns lei_present: false rather than an empty hierarchy that would read as 'no parents'.

The relationship graph is no longer American-only. Until now /api/v2/entities/{id} returned relationships extracted from SEC filings plus, as of today, global energy ownership. GLEIF Level 2 adds 56,188 corporate-hierarchy edges — 29,800 ultimate-parent, 26,174 consolidating-parent and 214 branch-of — taking the entity relationship graph from 209,093 to 245,256 edges. These edges never assert a stake: where GLEIF records no percentage, none is returned.

Search: /api/v2/search gains universe=registry, which searches all 3.39M GLEIF records by legal name or LEI. Registry results are deliberately kept in their own lane and never mixed into universe=all or universe=reference — a registry hit is a legal-entity registration, not evidence of news coverage, and each result carries resolved_in_spine telling you whether we also cover the entity itself.

Non-Latin company names now resolve. Entities we already cover picked up 18,699 alternative and transliterated names from GLEIF, 2,412 of them non-Latin. Searching a company by its registered Cyrillic, Han or Arabic name — for example the full Russian legal name of Alrosa — now returns the entity, where before it returned nothing.

★ Corrected: ownership relationships were being under-reported by a large margin, and the affected numbers are moving up sharply. Our global energy-ownership records store a parent company as an identifier with the ownership stake appended to it — for example `E100001011238 [47.5%]` — and every part of the system that read those records matched them as plain identifiers, so 82.4% of the ownership links never matched anything. Of 31,516 parent links, only 4,903 were resolving; now 30,878 do.

What that looked like: `ownership_edges.child_count` on the entity endpoint reported zero subsidiaries for some of the largest power companies in the world. China Energy Investment went from 0 to 139, Huaneng Power International from 0 to 102, China Cinda Asset Management from 0 to 112, and China Huadian from 2 to 129. There was no error and no warning — just an HTTP 200 with a number that was wrong.

Ownership-chain exposure was affected the same way, because the chain walk stopped after a single hop on 82.4% of edges and so never reached indirect owners. When the next daily exposure rebuild runs, expect exposed entity counts to rise substantially: sanctions exposure from 220 to 392, China exposure from 47 to 181, and state-ownership exposure from 1,372 to 2,339. If you have alerting or screening tuned against these, entities that previously came back clean may now come back exposed. This is a correction, not a change in method — those entities were exposed all along through ownership chains we were failing to traverse.

New: the ownership graph itself is now published. Until now `/api/v2/entities/{id}` returned only relationships extracted from SEC filings, which meant the relationship graph was entirely American. We have added 24,562 ownership edges covering global energy ownership, 19,668 of which carry a declared ownership percentage. They are typed `ownership` and are distinct from the `subsidiary` relationships extracted from SEC filing text: those are a legal-subsidiary claim read out of a document, these are a registry-declared stake. Where no percentage was recorded, none is asserted.

Fixed a bug in /api/v2/events/summary that reported a fabricated 0 for the four CAMEO+ metrics on events that do not have them. The three 0–1 metrics are stored as non-nullable floats, so an event with no CAMEO+ detail row was being averaged in as 0 rather than skipped. Measured over 7 days: all 1,074 Conflict-family events reported avg_systemic_importance = 0 instead of null, and 780 of 12,197 CAMEO+ events with no detail row pulled the CAMEO+ average down from 0.241 to 0.2255. avg, min and max for systemic_importance, propagation_potential and market_sensitivity now return null when no event in the bucket carries the metric. magnitude was already correct.

If you read /events/summary, expect these three fields to change: Conflict-family buckets now return null where they previously returned 0, and CAMEO+ averages move up slightly. A 0 asserted 'measured, and it is the minimum' about a metric that does not apply to that family, which is the opposite of what we intend — we omit rather than fabricate.

Events coded from today also return metrics.metric_inputs: the sub-factors behind each score with the reason the coder recorded for each one, so a score can be re-derived by hand. The field is absent (not empty) on events coded earlier, and on Conflict events, which have no sub-factor contract. A backfill of the existing corpus is planned but has not run.

The event-metrics documentation is now published at /event-metrics and in a dedicated Event Metrics section of the docs, with a page per metric covering the formula, the plain-language definition of every variable, worked examples from real coded events, and the measured error bars.

2026-07-27

The four CAMEO+ event metrics — magnitude, systemic_importance, propagation_potential and market_sensitivity — are now produced by published formulas rather than by a free-form model judgement, and the formulas are documented in full. The coder reads a handful of concrete sub-factors off the source text and records a reason for each; a fixed, versioned function turns those into the score. Any value can now be re-derived by hand from the inputs. The field names, ranges and response shape are unchanged, so no integration needs to change.

What each metric is grounded in: magnitude follows Richardson's log-fatality convention on the conflict path (2 + 2·log₁₀(deaths)) with anchored 0–10 tiers elsewhere; systemic_importance is the equal-weighted mean of size, interconnectedness and irreplaceability, matching Basel BCBS G-SIB and ECB O-SII practice; propagation_potential averages five observed transmission conditions behind a channel gate, following the ERCS barrier model and Rinaldi–Peerenboom–Kelly dependency coupling; market_sensitivity applies the reasonable-investor materiality test. We adapt these frameworks — none of the institutions named endorses or reviews this work.

★ Expect the default significance ordering to change. Because significance blends these four, re-coding moves it: measured across 59 paired real events with the formula held identical, rank correlation between the old and new values is 0.76, and 32 of 59 events move by more than 0.05. To be sure that was a real change and not coding noise, we ran the same events three times through the new path and compared: identical runs agree at 0.92, so the shift is larger than the noise. Verbal appeals and announcements deflate, real in-force action inflates. If you have alerts or thresholds tuned against current significance values, they will fire differently. sort=significance is the default on /api/v2/events, and Atlas Pulse and Posture read the same expression.

We now publish the error bars, and ask you to use them. Repeat coding of the same event moves magnitude by about 0.36 on its 0–10 scale and the three 0–1 metrics by about 0.03. Treat differences below roughly 0.72 (magnitude) and 0.07 (the others) on a single event as noise. Aggregates are far steadier than individual events, so distribution-level comparisons hold well below those thresholds.

Corrected how we describe these numbers, in several places where the wording oversold them. market_sensitivity is not a predicted price move — it measures how much market-relevant information an event carries for a reasonable investor, and carries no direction. propagation_potential is not a probability of cascade — it scores transmission conditions present in the event as reported, not a forecast. systemic_importance is not a count of affected states — it is how much the wider system depends on the specific node an event touched. And the published significance weights were wrong: fatalities is 0.55, log-scaled by body count, not 10%; civilian targeting (0.10) was missing; and the per-family renormalization that makes conflict and CAMEO+ events comparable was undocumented.

These four are rubric scores, not measurements, and the docs now say so wherever they appear. A hard registry attribute — the observable that would make systemic_importance empirical rather than judged — resolves for about 1 event in 45, and a traded instrument for about 1 in 67. Treat all four as ordinal ranking signals. magnitude is comparable within a domain only; use significance to rank across domains. A magnitude of null means the severity observable was not found — it means unknown, never zero, and should not be coerced to 0.

Fixed: Stories that already had a coded event but weren't linked to it now show it. A cluster's event id is derived from the cluster id, so a Story stuck in this state was re-analysed on every pass, the result discarded as a duplicate, and the link never written — leaving has_events:false permanently on a Story whose event existed the whole time. We swept the backlog: 1,414 Stories reconnected to their events. For Stories with 4+ articles the has_events:false rate fell from 60.4% to 58.0%, and the improvement scales with size — 6-9 articles went 49.5% to 40.0%, 10-19 went 58.9% to 45.1%, and 20+ went 57.7% to 43.8%. Going forward the link is written before the re-analysis rather than after, so the loop cannot re-form.

Fixed: big Stories that grew over the course of a day were being excluded from event coding. Every cluster is graded once when it is created, and a single-article cluster that isn't worth analysing is marked as such — but nothing re-graded it when it later accumulated articles. Stories that grew to hundreds of articles kept the original grade and were never analysed for events; the largest we found held 283. Codeability is now derived from the Story's current size rather than read from the grade stamped at creation, so growth is picked up automatically.

Duplicate Stories: the same-day de-duplication pass now spends its full comparison budget on pairs it hasn't seen. It was re-checking pairs already settled earlier the same day, which consumed about 70% of each pass. On a measured day this raised the range a single pass covers rather than truncating it. Half of the duplicate Stories removed on 2026-07-27 came from a similarity range the previous rule could not reach at all, and an independent audit put the false-merge rate at 3.3% — none of them in the newly reachable range.

Note on story_id stability: reconnecting a Story to its event does not change any story_id, and no Story was removed by this work. If you cache has_events, expect it to flip from false to true for some Stories dated on or after 2026-07-13.

2026-07-24

New: entity tone now breaks down BY LANGUAGE across all scored coverage in the window. Pass group_by=language to GET /api/v2/entities/{id}/tone (or /api/v2/entity-tone), and each entity's coverage gains a by_language array — mean tone, risk, and confidence per language, with the number of scored stories and the real total article volume covered in that language, plus a per-language daily series. It's also embedded in the entity-detail response under entity_tone.by_language when include_tone=true. The point is to see how an entity is covered differently across languages — e.g. an entity that reads markedly more negative in Arabic and Russian than in Spanish. The mean tone per language is computed over every scored story (not a sample); it reads the per-story score rollup because the daily table doesn't retain per-language splits.

Docs: the entities-detail response now documents the fields the endpoint has been returning all along but the schema omitted — cooccurrences (co-occurring entities: name, type, wikipedia_url, story_count, source, url), plus timeline, source_mix, map_pins, and the per-source sources/sections map. No response change; the OpenAPI schema and the MCP get_entity tool now describe them.

The "API view" drawer on the event, story, and entity detail pages now shows the exact call and the exact response the named endpoint returns — the promise that you can copy a snippet and get the same data back is now literally true. Previously these drawers reconstructed a stand-in body by hand, so several snippets returned a different shape than shown, and a few named sub-endpoints that were never actually built (for example /entities/{id}/cooccurrences or /stories/{id}/related). Each drawer now runs the same serve function the public endpoint does, so a copied cURL/Python/TypeScript snippet reproduces the drawer byte-for-byte. A verification gate fetched every shown snippet and deep-compares it to the drawer across the anonymous, free, and Intelligence tiers.

The entity drawer's snippet is now plan-aware. GET /api/v2/entities/{id} returns a body whose per-source sources map and gated sections depend on your plan, and the drawer now reflects the tier the page is being viewed at — so what you see is what your key would receive, and the public (signed-out) page never shows a body richer than the free tier. The event and story detail responses are unchanged.

2026-07-23

New: Media — entity Tone and Share of Voice now have their own place in the app at /media, with the two views side by side. Two fixes went with the move. Picking an entity alias from the suggestions (for example choosing "Israeli military" after searching IDF) used to report "No canonical entity match found" for an entity the API resolves perfectly well — the page recognised fewer id formats than the resolver behind it, and now uses the same one. And the Tone page no longer shows a Share of Voice figure: share of voice needs a peer set to divide by, the page only ever had a single entity, so the API was correctly refusing the request and the page was displaying the refusal as "0.00% · 0 of 0 stories". Share of voice is now only where a peer set is actually collected.

Tone's per-language breakdown now states what it is measured on. It is computed from a bounded evidence sample, not from every scored story, so its per-language article counts never summed to the scored total shown above it — a page reporting 258 scored stories showed language counts totalling 27, with the explanation in a footnote. The sample size is now labelled on the panel itself. Selecting a language still refilters the headline figures against the full window.

Entity pages no longer borrow another entity's portrait. For entities we have not linked to Wikipedia, the page was falling back to a Wikipedia search on the entity's name, which could resolve to a different organisation and show its logo beside the first entity's name and numbers. No link, no portrait — those entities now show initials.

The Core Search results pages are faster and show 10 results at a time with a "Show 10 more" control. Typing in the search box no longer fires a search per keystroke — it now runs on Enter or the Search button, which matters because this is a semantic search that embeds the query and runs a vector lookup each time. Card imagery is now opt-in from the filter bar, because fetching it was the single largest cost in the response.

GET /api/v2/events and /api/v2/stories now honour include_entity_images. It was accepted but ignored, so callers could not turn off the per-entity Wikipedia enrichment that dominates response time on image-bearing requests. It defaults to true, so existing callers are unaffected.

Fixed a silent under-return on GET /api/v2/facilities. Filtering by status matched the stored value exactly, but Global Energy Monitor records inferred states as their own values ("shelved - inferred 2 y", "cancelled - inferred 4 y"), so status=shelved returned 39% of shelved facilities and status=cancelled 71% — while reporting the filter as applied. Status now matches on the base state, and those filters return the full set.

New: Core Search — one signed-in surface at /search that browses the Core API groups (events, stories, entities and facilities) behind on-page tabs, with every result linking through to its own page. Switching tabs carries your query and date window across, so the same search can be viewed as events, as stories, or as the entities involved. Each tab is a live call to the public endpoint it demonstrates, and the "API view" panel now shows the request and the complete, unmodified response body — previously it displayed a shortened stand-in rather than the real payload, so the copyable cURL / Python / TypeScript snippets could return something different from what the page showed. They now reproduce the page exactly.

Facilities now has a UI. The fused directory (power plants, mines, pipelines, terminals, ports and AI data centers from Global Energy Monitor, the NGA World Port Index and Epoch AI) is searchable by name, owner, type, class, source, country, status and capacity, and every facility has its own page with location, resolved owner entities, the source record and the license attribution. Signed-in users additionally get the full owner list, every source attribute, the cross-silo merge history, and recent news coverage of the facility's owner over a 7-, 14- or 30-day window. Facilities is included from Builder up.

Fixed pagination on GET /api/v2/stories in the web app. Stories pages with a keyset cursor, and the Next control had been computing a numeric offset instead of passing the cursor the API returns — the server could not decode it and silently re-served page one. Paging forward now advances correctly. The API itself was always correct; this was the web app mis-using it.

Semantic search on GET /api/v2/events (the search / query parameter) is now backed by the vector index end-to-end. It had been running an unindexed similarity scan over the whole requested date window, which made larger searches slow and, under concurrent load, run up against the query time limit — the source of intermittent errors on the events search endpoint. It now ranks against the HNSW index and hydrates only the top matches; the result ordering is unchanged (same cosine-similarity relevance), and a representative 30-day search dropped from around eleven seconds to well under a second.

The query-embedding step that powers semantic search now retries a transient timeout instead of failing the whole request. A slow embedding call had been surfacing as a hard 503 SEMANTIC_SEARCH_UNAVAILABLE on /api/v2/events and /api/v2/stories; it is now given more headroom and retried, so those intermittent search failures are largely eliminated. A genuinely unavailable embedding service still returns an honest 503 rather than silently wrong results.

Semantic search now honours sort and exposes a relevance score. A bare search returns results in relevance order (most similar first) and reports sort:"relevance"; sort=significance or sort=recent now re-rank the relevant matches by significance or recency, whereas before sort was effectively ignored once a search term was present. Every result carries a search_score (0–1, higher = closer) so you can threshold on match quality, and on /api/v2/events a low-relevance floor drops nonsense/no-match queries to an empty result instead of returning confident-looking but irrelevant events. Forward pagination via next_cursor on /api/v2/events?search= is also fixed — it previously stopped after the first page.

Entity ids are now consistent across every endpoint. The id returned by GET /api/v2/entities is now the same universal canonical id that GET /api/v2/search returns — an e_… id when the entity is in our cross-source reference spine, otherwise a wiki:… id — and it round-trips on every entity-taking endpoint (/events?entity=, /entity-tone, /share-of-voice, /gov/awards?entity=, entity detail). Previously the entities list handed back a name-based id (person:Name / organization:Name) that resolved on some endpoints but was rejected by the cross-source ones, so chaining calls could silently drop data. Old name-based ids still resolve, so existing integrations keep working; new responses simply return the canonical id. The Wikipedia URL is unchanged and still returned as the wikipedia_url field.

2026-07-22

Corrected the end-to-end latency figure, which we had been quoting as "about 15 minutes" across the site. That number was the ingest pipeline's own duration mistaken for end-to-end latency. Measured directly (median over the seven days ending 2026-07-21, from an article's publication to the coded event being queryable in the API): the median is 38 minutes and the 90th percentile is 61 minutes; 10.7% of events are available within 15 minutes and 89.1% within an hour, with a longer tail for events recovered by the hourly catch-up pass and by backfills. The floor is the hourly ingest cycle, not processing time. The methodology and pricing pages now carry the measured distribution instead of the old estimate.

Corrected the native-source compliance handling. Each native RSS/sitemap source carries a declared content policy (blocked, metadata-only, or cleared-for-extraction); the pipeline was overriding that declaration and processing every source at full extraction. It now honors each source's declaration, so a source is processed for full article body only when it has been explicitly cleared, and the stored compliance status reflects a real decision. The methodology page's source-universe section describes the three tiers precisely.

New: the Atlas Coverage Atlas — GET /api/v2/intelligence/coverage (Intelligence plan) and a map on the Atlas product page. It reports, per country, how much coded-event coverage we actually have and therefore which country-level Atlas products each country is dense enough to serve — distinguishing the roughly five dozen countries that clear the slower Posture condition-index floor from the roughly fifteen that clear the higher bar for a daily Pulse tension reading. The exact live counts are published by the endpoint itself rather than fixed here, since coverage grows over time. Rather than print a confident score for every country, it shows the rest as thin or empty. Filter to the daily-servable and condition-servable sets with ?tier=depth.

GET /api/v2/events now reports geo_precision on every event's geo block — a code (1 exact place, 2 general area, 3 country or region centroid) and a matching label — so you can tell an exact-place fix from a country centroid instead of treating every coordinate as precise. You can also filter on it: geo_precision_max=1 returns only exact-place events, which is what you want before triggering on a specific asset. Across a recent sample about a third of events are exact-place and roughly two-thirds carry an area or centroid coordinate.

The events endpoints now reject as_of with a 400 instead of accepting it and returning live data. as_of implies a reproducible point-in-time read; the Atlas and macro series are vintaged and honour it, but event metrics are computed live and are not, so accepting it would have returned today's values while implying otherwise. Use observed_start / observed_end to bound by when an event was coded, or the Atlas and macro endpoints for point-in-time reads.

Fixed a composability break: the entity_id that GET /api/v2/search returns (a registry id of the form e_…) now works as the entity filter on /api/v2/events, /api/v2/events/summary, and /api/v2/stories. Previously that id resolved to nothing on those endpoints and returned an empty result — a false "no events" — while the entity's name worked; you had to know to pass the name instead of the id you were just handed. The shared entity resolver now bridges a registry id to the news-layer identity the event surfaces are keyed on, so search → id → events is a clean round-trip. Verified across TSMC, Boeing, Gazprom and Volkswagen: the id returns exactly what the name does.

2026-07-21

Atlas now has a public page at /product/atlas, with real screenshots of the GPR and Posture surfaces and the coverage caveats stated up front. It is labelled experimental deliberately: world and continent readings are usable daily from April 2026, but country coverage is thin — measured over 107 days, only 2 countries clear the per-country coverage floor on 90 or more days and 12 clear it on most days, and every other country returns null rather than a fabricated score.

Corrected the Atlas entitlement across the site. The /api/v2/intelligence/gpr and /posture endpoints are gated on the Intelligence plan and have been since the plan simplification, but the data reference and the methodology page both still described them as Admin-only or an internal preview. Both now match the code.

The homepage carries a measured throughput and coverage band — articles processed, stories clustered, events coded and entities resolved over the last 30 days, read live from the same database the API serves and refreshed hourly. It renders an explicit unavailable state rather than zeros if the reading fails.

The comparison (/compare) and industries (/industries) page trees have been retired and now redirect. They carried a hardcoded price range that no longer matched the published plans, and the pricing page, data reference and use-case pages cover the same ground against live data.

Corrected several stale claims: media tone and share of voice are computed over news coverage only and social posts are not blended into them (the FAQ previously said otherwise); the REST API and MCP server are included on every plan including the free tier; the CAMEO+ taxonomy has ten domains; and the Early Signal index now regenerates hourly rather than only on deploy. (The latency figure standardized here — "about 15 minutes" — was itself an estimate of pipeline duration; it was later measured directly and corrected in the 2026-07-22 entry.)

2026-07-20

New endpoint: GET /api/v2/intelligence/posture — Atlas Posture, a country condition index. Where Atlas GPR measures how hot a place is running against its own norm, Posture measures what state it is in, scored against fixed real-world reference points. It returns a 0–100 composite over four published pillars (Conflict & Security 0.35, Systemic Gravity 0.25, Markets & Economy 0.25, Flows & Contagion 0.15), each pillar's sub-indicators, a fixed band (Calm / Steady / Elevated / High / Critical, plus a neutral L1–L5 form), the pillar driving the score, and a trend arrow. Every pillar is also split into internal and external readings by whether an event's actors sit inside one country or span a border. Accepts country or level+geo, window=7d|30d|90d (30d default), date, as_of for point-in-time reads, and scope. Included with Intelligence.

Posture withholds more than it publishes, by design. A geography is scored only when its window clears a coverage floor, and each sub-indicator also requires a minimum denominator of its own — a share computed over two events can land anywhere in the distribution. About 60 countries currently clear the floor over 30 days; the rest return null with an insufficient-coverage flag rather than a fabricated number. A well-covered country with no violence does report zero, because that is a real measurement. A fifth pillar, Narrative & Information, is specified but deliberately not shipped — the inputs are not dense enough at country-day granularity — and responses name it as deferred rather than omitting it silently.

Posture values are computed daily and stored point-in-time, so an as_of query never looks ahead: a day revised by late-arriving events keeps its original vintage alongside the correction. Scores, bands and trends are derived at request time from a frozen cross-country reference, which means re-baselining adds a new version rather than rewriting history. The index is provisional while its reference distribution is pooled over a short window.

Posture also gains a second, slower axis: structural condition. Alongside the event-derived pillars, it now scores the standing institutional and material condition a country brings to any week — governance quality and rule of law (World Bank Worldwide Governance Indicators), how democratic the regime is (V-Dem electoral, liberal, civil-liberties and free-expression indices, newly loaded for 176 countries from 1990), development, economy, and militarization. Governance and democracy are deliberately separate dimensions: the World Bank measures whether a state is effective, V-Dem measures whether it is democratic, and the two come apart routinely. These inputs are annual and lagged, so this axis is slow by design — it describes the ground a shock lands on, not the shock.

The structural axis is scored against fixed good/bad anchors on each indicator's own scale rather than against a live cross-country ranking. A rank is zero-sum: it pins any world or regional aggregate near the middle no matter what is happening, and lets a country's score improve only because another country's got worse. Anchoring means a country's structural score depends only on its own condition and an aggregate becomes a real number that can move. Indicators whose meaningful range is multiplicative, such as GDP per capita, are anchored on a log scale.

2026-07-19

Entity Dossier is now included with Intelligence. GET /api/v2/entities/{entity_id}/dossier returns one entity's statecraft timeline — sanctions designations, FARA foreign-agent links, federal awards, coded events and tone in a single cited chronology, resolved across both the news and registry identity universes so government data and events line up. It was built and reachable only on internal plans; it is now part of the Intelligence tier and Enterprise. Atlas indices are likewise no longer marked "preview" in API responses: they have been included with Intelligence since the plan simplification, but every response was still stamped preview:true, which understated what the tier includes.

Energy assets moved from Core Data to Open Feeds. The /api/v2/energy/* endpoints serve Global Energy Monitor's published registries close to as-published, so they now sit with the other open feeds (government, filings, AI & compute, macro, risk, maritime) rather than alongside the events, stories and entities we produce ourselves. They are included from Analyst up. Existing Builder subscribers keep raw energy access — no action needed. The fused facilities directory (/api/v2/facilities), which is our own cross-silo join and owner resolution over GEM, the NGA World Port Index and Epoch AI, stays in Core Data and is unchanged from Builder up.

Fixed: the subscription page listed retired plans. Signed-in accounts with billing-alpha access saw the full historical plan list on /settings/subscription — including internal states that are not products — while /pricing correctly showed the four current tiers. Both surfaces now render the same catalog, plus your own plan if you are on a retired one.

2026-07-18

Simpler plans. The eight public tiers and five à-la-carte modules are now four plans, each a strict superset of the one below it: Free, Builder ($79/mo), Analyst ($399/mo) and Intelligence ($899/mo), plus Enterprise. Plans are organised the same way the API Arena is — Core Data (the events, stories, entities and facilities we produce), Core Analytics (media tone and share of voice), Open Feeds (government, filings, energy, AI & compute, macro, risk and maritime) and Intel (Briefs, alerts, the research agent and Atlas indices). Intelligence now includes every open-data feed, so the modules that used to be bought separately are simply included. The previous tiers — Monitor, Media Intelligence, Corporate & Supply Chain and Global Intelligence — are retired for new signups.

Existing subscribers keep everything. If you are on a retired plan you keep your plan, your price and every feature you have today; nothing changes and no action is needed. If you are on Builder, Analyst or Intelligence you keep the price you subscribed at, and your limits only go up — Analyst rises from 12,000 to 20,000 QU and 90 to 120 requests/min, and Intelligence from 180 to 300 requests/min with more included Briefs.

Query Units are now easy to size. Because our data refreshes hourly, keeping one entity, topic or query current costs about 750 QU a month — polling faster returns the same answer. Divide a plan's QU by 750 to get the number of things you can keep current: roughly 3 on Builder, 27 on Analyst and 137 on Intelligence. The pricing page states this rule directly, and Briefs continue to be metered separately and never draw down your query units.

Bounding-box filtering now works on Stories. /api/v2/stories and /api/v2/stories/summary accept bbox=lat_min,lon_min,lat_max,lon_max and keep stories with at least one linked event inside the box — the same linked-event geography semantics as country and admin1. Previously bbox was accepted on these two endpoints but silently ignored, so a bounded request quietly returned the global feed. Note that linked_event_count and fatalities remain full-story aggregates rather than box-restricted, and malformed or out-of-range values now return 400 INVALID_BBOX.

The published API reference now matches the live surface. We reconciled the OpenAPI spec and docs against the serving code: filters that worked but were undocumented (languages, include_images, seasonal_adjustment, foundry, filings country, and the full China project filter set) are now documented; parameters the server rejects or ignores were removed; and endpoints that shipped some time ago are no longer labelled "coming soon" or admin-only when they are in fact plan-gated and generally available.

New Atlas GPR — a Geopolitical Risk index built from our own coded events, in the tradition of the Caldara–Iacoviello GPR. A reading of 100 means a place is at its own 90-day norm, 200 means twice its usual, so countries stay comparable to themselves rather than to each other. Two lenses: Events (coded-event tension, decomposed into Threats, Acts, Material and Verbal) and Attention (the share of news attention that is tension-bearing — the lens closest to the original GPR). Places below the coverage floor return no reading rather than a fabricated zero. The page moved from /dashboard to /atlas and adds a world choropleth, a 30-day time machine, and per-country hover showing that country's top event or narrative. Atlas is a preview: the page is open to every signed-in user, while GET /api/v2/intelligence/gpr stays on the Admin plan until the history and evaluation gates pass.

2026-07-16

New API Arena — a single, live demo of every GDELT Cloud endpoint. The Arena consolidates the old API Playground and the per-source list pages (Events, Stories, Entities, Energy, Screening, and more) into one results-first surface: pick an endpoint from the left rail, fill real inputs with sensible defaults, and see the rendered result full-screen alongside a raw-JSON toggle and copyable curl/Python/TypeScript. Endpoints are grouped into Data (our feeds) and Intel (the Atlas indices; Briefs and Alerts are marked coming soon). Every request is a real, metered API call (1 QU). Any request is shareable and deep-linkable via its URL. The old page paths now redirect into the Arena.

2026-07-15

Broader global coverage — more events, especially from under-represented regions. Until now a single-source story was only coded into an event if it cleared a signal score that rewarded well-known publishers and heavy entity tagging — which quietly favoured large Western outlets and dropped genuine events reported by regional and non-Western sources. Coverage now follows what the article reports, not where it was published, with priority given to China, the Middle East, Africa, and Eastern Europe. Expect materially more events from those regions (arrests, protests, sanctions, corporate and infrastructure actions), with the same coding accuracy.

The event coder now runs on a more capable model across the board (see the 2026-07-14 note), so classification and location accuracy improve for every event, not just the newly added ones.

Deeper coverage of major, fast-moving stories. A new catch-up pass codes large multi-source narratives that build up across the day — summits, ongoing conflicts, disasters — that the hourly pipeline previously left uncoded. These now surface as events on /api/v2/events and in story feeds, without introducing duplicates.

More reliable ingest on the busiest news hours. The pipeline now persists its clustering before the coding stage, so if a heavy hour runs long, that hour's events are recovered by the catch-up pass rather than lost.

2026-07-14

Event coding accuracy: mis-classified events cut by 60%. We audited the coder by re-reading the exact source articles behind each event it produced and judging the event against them. On a random sample of 139 live clusters, 36% of coded events were wrong about their own sources — the wrong CAMEO+/ACLED type, or a location the text did not support. Three fixes bring that to 16%: (1) the coder now runs on a mid-tier model, because assigning a 200-code taxonomy to unstructured news is adjudication, not a small-model task; (2) it is no longer locked into the code family guessed from headlines — a router that reads only titles was pinning the coder's choices to a subtree that sometimes made the correct code unreachable, turning a routing miss into a guaranteed coding error; (3) each code now carries its official codebook definition, so a threat to impose sanctions is no longer confused with sanctions actually imposed, and a threat of military force is coded as one.

Events are no longer dropped because a news article did not date itself. The coder was instructed never to infer an event's date from the article's publication date, and to refuse anything lacking explicit same-day date evidence. Most news copy never states a date — it simply reports what happened — so the instruction, read literally, meant refusing most of the feed. Real arrests, protests, court verdicts and an airstrike were being declined for the sole reason that the article did not say 'on Wednesday'. An article reporting an action as current news is now presumed to be reporting it from that news cycle, and is dated to the source day unless the text places it earlier. Reports that explicitly describe older, background, anniversary or cumulative events are still excluded.

Story significance is now attention — the number of articles covering the story. It used to be 65% event-severity + 25% article count, which hard-capped an event-less Story at 0.35 no matter how large it grew. Because the biggest accreted narratives are the ones least likely to carry a coded event, that formula inverted attention: a 1-article Story with an event outranked a 265-article narrative, and the day's most-covered Story never appeared in the default ranking at all. Sorting by significance now means sorting by coverage. Event severity is unchanged and still returned separately as metrics.max_linked_event_significance.

Far fewer duplicate Stories. Same-day reconciliation only compared clusters that shared 3+ literal words in their headlines AND sat in the same category — a lexical gate on top of a semantic system. It was discarding real duplicates before they were ever considered: on one day it hid 1,157 of 1,373 true candidate pairs (84%), leaving a single story split across six live clusters. Candidacy is now decided by meaning alone (every cluster pair is compared), and every candidate is adjudicated by a model before anything merges. Expect materially fewer near-identical Stories, and article counts that reflect a narrative's true footprint.

Stories now count events that lag one day behind their cluster. An event whose date falls in the previous UTC day from its story's cluster date (a normal effect of the prior-day ingest window) was being dropped by the story's linked-events aggregation — so a story viewed on a single day (story detail / public story page) could show fewer, or zero, linked events than it actually had. The window now includes the one-day lag, recovering those links. Counts only ever increase toward the true value; no story loses events. Affects linked_event_count, the has_events filter, and story summaries.

2026-07-13

More reliable Event→Story links. When an event's story cluster is merged into a larger one during same-day reconciliation, the event's story reference now resolves to the surviving live story instead of occasionally pointing at a merged-away cluster (which returned a STORY_MERGED 404). Events on /api/v2/events and the per-event lookup now return their correct live story_refs / primary_story_url — or an explicit empty story when no live story exists — never a broken link.

Reconnected orphaned events. Events coded from clusters whose entire lineage was later merged away are reconnected to their live story via a semantic (embedding + LLM) match, recovering the story context they had lost. This runs forward automatically and was backfilled across recent weeks. No response-shape change — reconnected events simply resolve to a real story.

New endpoint: GET /api/v2/events/{event_id}/stories. Returns the live story cluster(s) an event belongs to, including a reconnected event's re-homed story. Each entry carries a relation of primary or reconnected, so you can tell a canonical link from a recovered one. Optional start_date / end_date narrow the window.

Consistent event→story links everywhere. The per-event story link in the Entity endpoint (/api/v2/entities/{entity_id}) now resolves through the same live-story logic as /api/v2/events, so chaining the two endpoints always agrees on which story an event belongs to — and shared story cards prefer the live cluster over a merged-away one.

2026-07-12

New Prediction Markets API (admin preview) — market-implied probability as economic-intelligence signal. /api/v2/markets serves an owned daily snapshot of geopolitically-relevant Kalshi prediction markets: implied YES probability, volume and open interest, and the market's resolution once it settles. Filter by a resolved entity (the same canonical entity selector as every other endpoint), category, theme, series, or FRED-linked markets only.

Bitemporal as-of + related FRED-series context. Pass as_of=YYYY-MM-DD to read the implied probability we captured on or before that date — no look-ahead. For macro markets (Fed, CPI, GDP, oil), the per-market view adds the point-in-time path of the related FRED/ALFRED series the market's family maps to — context on what the underlying macro series actually printed alongside the market's probability, each labelled with when it was known (it is related context, not the market's settlement — that is the separate resolution field). Market-implied probability is context/signal, not trading advice; unknown coverage is null, never a fabricated 0. Currently an admin preview (like the Dossier); plan availability will be announced at general availability.

2026-07-11

Sharper Monitoring Briefs — we upgraded the model powering Briefs to OpenAI's newer gpt-5.6 generation. In our head-to-head evaluations the new writer produced better-grounded briefs — roughly twice the GDELT evidence cited per brief — at a lower token cost, and the research step that gathers evidence now surfaces more source material. No change to how you request or receive a Brief.

2026-07-11

API normalization — a canonical entity selector. /api/v2/facilities and /api/v2/energy/assets now accept a single canonical entity parameter: pass a resolved spine id (e_…) for an exact owner match, or any name for a case-insensitive fuzzy owner-name match. Using one consistent selector means you can reuse the same entity identifier as you chain calls, instead of learning a different owner field for each endpoint.

Alias-and-deprecate — nothing breaks. The legacy owner_search parameter is now marked deprecated in the API reference but remains fully supported; owner_entity_id continues to work as the explicit opaque-id form. No parameter or response field was removed.

Uniform pagination — the Epoch AI endpoints now return next_cursor. The /api/v2/epoch/* endpoints (models, hardware, data-centers, companies, chip-sales) gained a canonical next_cursor page token and accept cursor as the page-token input, alongside the existing next_offset / offset (now marked legacy but still returned). Follow pagination.next_cursor and pass it back as ?cursor= — the same cursor loop already used by the Events, Stories, Facilities and Energy endpoints.

2026-07-11

New Foreign Agents (FARA) API — the US foreign-influence graph. /api/v2/gov/fara returns DOJ FARA registrations linking a US registrant (a law / lobbying / PR firm) to the foreign principal it represents, both resolved to the entity spine. Filter by a resolved entity (either side of the link), a fuzzy registrant or foreign-principal name, or a country. Available on the Markets plan and up (can_use_gov).

Fused to our sanctions data — the differentiator. sanctioned_only=true returns only links whose foreign principal is on one of our screening lists (OFAC SDN, BIS Entity List, DoD 1260H, OFAC CMIC, UK), with the specific lists and sanction programs attached — so you see US firms registered as agents for a sanctioned entity, not merely for an adversary country.

Also on the MCP server (gov_fara in the gov category) and in the API Playground (a Foreign Agents card with live examples). Data provenance: FARA is US public domain (DOJ NSD FARA eFile), one row per (US registrant, foreign principal) link.

Government responses now carry a cross-source footprint. /api/v2/gov/awards and /api/v2/gov/fara (and the entity Government panel) add a cross_source block for the resolved entity — its foreign-agent status (including principals on our sanctions lists), whether it's an SEC filer, and how many mapped facilities it owns — plus headline flags like “federal contractor + foreign agent” and “foreign agent for a sanctioned entity.” One lookup, the whole spine: which US firms take federal money and lobby for foreign or sanctioned governments — a join no single-source viewer offers.

2026-07-10

New Government exposure API — an entity's US federal award footprint. /api/v2/gov/awards returns an entity's USAspending federal award timeline (prime contracts + grants) with a per-recipient rollup — total obligated, awarding agencies, first/last action date — resolved to the entity spine and keyed on the SAM.gov UEI. Look a recipient up by a resolved entity id, a SAM.gov UEI, or a fuzzy name. Available on the Markets plan and up.

Fused, not siloed. Because recipients resolve to spine entity ids, federal spending joins the live Events / Stories / Entities / Facilities graph — from one entity you can pivot to its awards, the facilities it owns, and the events nearby.

Same surface on the MCP server (the gov category: gov_awards) and in the API Playground (a Government card with live examples). Both share the can_use_gov gate.

Data provenance: federal awards are US public domain (USAspending.gov), keyed on the SAM.gov UEI — Dun & Bradstreet DUNS numbers and the D&B corporate-family tree are excluded by license and never surfaced.

An EPA ECHO enforcement surface (facility-level violations and penalties, geo-matched to the facilities directory) is in development and will follow once its operator-attribution precision bar is met.

Stories pagination now walks the entire result set. /api/v2/stories moved from offset to keyset (seek-after) cursors: follow pagination.next_cursor until it is null to page through every story in your date window. Previously the cursor silently stopped at ~1,000 stories per query — a single busy day can hold well over 10,000 — so long walks were being truncated with no error.

What to do: keep reading pagination.next_cursor and passing it back as ?cursor=… — same loop as before. The token is now an opaque string rather than an offset number, so treat it as opaque (a hand-crafted numeric ?cursor=N is no longer honoured on this endpoint and restarts at page 1). sort=significance (default) ranks by significance; sort=recent gives a strictly chronological walk. Semantic search (?search=) is unchanged — it stays a relevance-ranked top-K, not a full walk.

2026-07-09

Entity Tone & Share of Voice now accept spine entity ids and typed ids. You can pass an e_… id straight from /api/v2/search — or a person:/organization: id — to /api/v2/entity-tone or /api/v2/share-of-voice and it resolves to the same entity the series is keyed on (previously a spine id returned 400, and a typed prefix could bind to a wrong same-name fragment). Resolution by plain name is unchanged.

API Playground refreshed. Every endpoint now ships a tight set of 2–3 diverse, verified examples — each confirmed to return live data — Entity Tone leads with a broader cross-sector set (politics, energy, defense, plus a per-language English-vs-Chinese example), and the Briefs card was removed. Entity Tone and Share of Voice now render as visual cards — a diverging tone trendline with a reputation-spectrum read (and separate risk view), and a share-over-time chart — instead of a raw field table, and no longer show an empty state on responses that actually have data. No REST API changes.

Facilities directory expands to heavy industry and reorganizes ports. /api/v2/facilities now includes ~5,700 GEM heavy-industry production plants — steel, cement, and chemical — plus iron-ore mines, each geolocated and (for cement/chemical, at ~100%) resolved to its owner on the entity spine. New facility types: steel_plant, cement_plant, chemical_plant, iron_ore_mine.

Maritime ports are now their own category. `port` moves out of transport_logistics into a dedicated `ports` class, and a new `heavy_industry` class groups the steel/cement/chemical plants — so the coarse class filter is now power / extraction / transport_logistics / ports / heavy_industry / digital_infrastructure (21 leaf types in total, ~216,400 facilities).

The new types and classes are live across the REST API, the MCP facilities tools, and the API Playground.

Better facility geography. All 67 AI data centers are now geolocated (previously coordinate-free), and ~4,950 gas & oil pipelines carry their route geometry (from GEM's published GeoJSON) plus a representative point — so data centers and pipelines now render on maps and respond to the near / bbox geo filters. Point-geo coverage across the directory is now ~99%.

2026-07-08

New Facilities API — a unified physical-asset directory. /api/v2/facilities puts energy assets (Global Energy Monitor), ports (World Port Index), and AI data centers (Epoch AI) on one keyed surface, each resolved to its owner entities on the spine, so you can ask what exists where, of what type, and who operates it. Filter by name, facility type or coarse class (power / extraction / transport & logistics / digital infrastructure), source, country/region/continent, owner (name or entity id), status, capacity (MW), and geography (bounding box or radius); fetch one facility with /api/v2/facilities/{facility_id}. Available on the Analyst plan and up.

Search or pivot by owner. Every facility carries its owners as spine entity ids, so a facility chains straight into the unified entity graph (news, filings, exposure, screening) — and owner_entity_id returns an operator's entire cross-silo portfolio in one call.

Same directory on the MCP server and in the API Playground. The facilities_search / facilities_get / facilities_by_owner tools mirror the REST surface for agents, and a Facilities card in the Playground exposes the full filter set with live examples.

v1 is directory-only (Epoch data centers ship without coordinates for now); the facility-to-event fusion is a separate upcoming stream.

2026-07-06

Entity list metrics now match entity detail. The entities list (/api/v2/entities) previously counted activity over the last 24 hours while the entity profile counted 30 days — so a list row could read 0 articles for an entity its detail showed as highly active. The list now uses the same 30-day default window, and a row with no in-window coverage no longer carries a stale last-seen date. Each list result also returns a resolvable id that round-trips directly into /api/v2/entities/{id}.

New severity tier on events. Every event now carries metrics.severity_tier (critical / high / medium / low) derived from casualties, civilian targeting, and escalation magnitude — an absolute band you can alert on, independent of the continuous significance score. Relatedly, significance now weights fatalities by body count, so a mass-casualty attack ranks above a zero-casualty diplomatic event.

Cleaner geographic rollups. group_by=country summaries now render readable names for aggregate and territory codes (European Union, Worldwide, Tuvalu, …) instead of leaking raw ISO/region codes, and an empty-country bucket is labelled Unknown rather than appearing as null.

Energy assets are better connected and clearer. Asset owners now carry a spine entity id where resolvable (so an asset chains into the unified entity, exposure, and screening); Heavy-Industry assets (iron & steel, cement, chemicals, iron-ore) are queryable on /api/v2/energy/assets via tracker=…; a new group_by=start_year (and decade) returns annual build-out; and asset rows no longer surface a placeholder 1970-01-01 date.

Share-of-Voice responses now use the standard {success, data} envelope like every other endpoint (the existing rows/status fields are retained for compatibility), and the semantic-denominator query is far faster and no longer intermittently times out. China development-finance responses carry an explicit coverage window (AidData GCDF 3.0, commitments through 2021) so the historical dataset isn't read as live. Unknown /api/v2/epoch/* paths now return a JSON error instead of an HTML 404.

The redundant /api/v2/entities/resolve endpoint is retired — use /api/v2/search, which returns the same resolution plus cross-source identifiers and a per-source availability map.

2026-07-06

Consistent country handling across the API. Any endpoint that filters by country now accepts a country name (United States), an ISO-2 code (US), or an ISO-3 code (USA) — plus common aliases like UK or Czechia — interchangeably, instead of each endpoint silently returning zero rows on the “wrong” code. An unresolvable value returns a clear 400 (INVALID_COUNTRY) listing the accepted forms.

Richer filters on the preview surfaces. AI models and hardware can now be filtered by publication/release date (date_start / date_end) and models by accessibility tier (open-weights, API access, hosted, unreleased); SEC filer relations can be filtered by counterparty jurisdiction and now include partner relationships; China development-finance projects can be filtered by project completion year; and events gained a point-radius proximity filter (near=lat,lon or lat/lon with radius_km).

Completed value pickers. The documented enums now list the full sets an endpoint accepts — the 19 AI-model domains, 11 hardware types, and 6 accessibility tiers; the 11 material-event types (8-K) including disposition, restructuring, impairment, delisting, and bankruptcy; and the full SEC relation kinds — so the API Playground and reference show every valid option.

Cleaner workflow chaining. Cross-source results round-trip on a single canonical entity id — resolve or search an entity, then pass its id straight into exposure (which now auto-selects the entity lens for you), tone, filings relations, or energy owners without reformatting. The API reference and Playground are reorganized from data-source silos into use-case groups — Events & Narratives, Entity Intelligence, Media Intelligence, Risk & Screening, Company Filings, Energy & Industry, Maritime & Trade, Markets & Macro, and AI & Compute — so the screening, media-intelligence, and cross-source join endpoints are discoverable instead of buried.

2026-07-06

Unified cross-source entity search is sharper and faster. A single query now fuzzy- and semantic-matches across every source — news, SEC/EDGAR, Global Energy Monitor, sanctions lists, China development finance, and Epoch AI — and returns one result per real-world entity with a normalized type (person, company, government, state body, …) instead of source-specific labels or a generic “entity”. Each result carries a per-source availability map, and its cross-source links now round-trip cleanly into the matching entity profile.

API Playground now shows an IDE-style code view that defaults to Python, and the curl / Python / Node snippets are the same literal call across every tool and result — copy-paste runnable, with path parameters placed in the URL. Preview showcases (AI Compute, Maritime, Unified Search) gained richer parameters and ready-made presets.

Data-quality fixes across preview surfaces: Epoch AI model filters return correct results for the frontier flag and expose real JSON booleans plus an applied-filters echo; the China development-finance endpoints accept the common parameter aliases; restricted-party list queries validate their inputs; entity Media Tone timelines render consistently; and unified entity search returns cleaner, less noisy results.

2026-07-05

Plans restructured around use-cases, and the advanced data modules go GA. The paid ladder is now segment-named — a Monitor tier for team event/story monitoring, Media Intelligence (tone + Share of Voice), Corporate & Supply Chain (SEC filings, supply-chain & sanctions/ownership risk, macro), Geopolitical Intelligence, and Global Intelligence — plus a custom Enterprise tier. Each plan card lists exactly which data modules it includes, and modules are attachable à-la-carte on lower tiers.

SEC EDGAR filings, FRED/ALFRED macro, maritime AIS signals, Epoch AI compute data, screening-list context, ownership exposure, and China-Abroad move from internal preview to plan-gated general availability (rolling out with the new plans). API responses for non-entitled keys return 403 with code PLAN_REQUIRED instead of ADMIN_REQUIRED.

Risk Context (screening lists, ownership exposure, China-Abroad) ships as best-effort, cited reference context — not a compliance product; see the new Risk Context section on the methodology page for provenance, cadence, and appropriate-use boundaries.

Share of Voice API requests are now bounded for reliability: at most 25 entities per request and a 92-day date window (error codes ENTITY_LIMIT_EXCEEDED / WINDOW_TOO_LARGE).

Existing subscribers are grandfathered: your price does not change, and your plan gains the modules added to its tier.

2026-07-04

Global Energy Monitor Heavy Industry — cement, chemicals, and iron-ore assets now join iron & steel on entity pages.

An entity's page shows the cement plants (3,515 tracked), chemical plants (868), and iron-ore mines (949) it owns, resolved through the GEM ownership graph into the unified entity registry.

2026-07-04

New Epoch AI dataset (CC-BY 4.0) — AI models, ML hardware, AI data centers, and chip sales, unified into the entity registry.

Entities like NVIDIA or Anthropic now surface the AI models they developed, hardware they make, data centers they own, and cumulative chip sales. Admin preview, with a dedicated /ai explorer, an AI & Compute section in the API Playground, and the /api/v2/epoch/* API.

2026-07-04

Homepage live 'Entities' counter now reflects our resolved/unified entity layer. It previously counted raw Wikipedia-linked mentions, which lag ingestion by 1–3 days and undercount; it now reports distinct resolved canonical entities over the last 24 hours.

2026-07-04

Energy & industrial assets on entity pages. For companies tracked by Global Energy Monitor — steelmakers, power producers, and their parents — profiles now show an Energy & Industrial Assets panel: the iron & steel plants they own (with steelmaking capacity) plus their ownership graph. This is included on every plan.

The entity API response is now organized into per-source sections. Alongside the existing fields, /api/v2/entities/{id} returns a `sources` map describing each data source for the entity — news, coded events, media tone, energy assets, share of voice, SEC filings, sanctions screening, and China development finance — each marked available and entitled, so you can see at a glance what an entity carries and what your plan unlocks. Each source is now an independent, per-plan feature; a source your plan doesn't include returns a uniform locked state that never discloses whether the entity has that data.

Homepage story count deduplicated. The 24-hour “stories” total on the homepage previously counted merged-away near-duplicate clusters, inflating it by roughly 15%. It now uses the same deduplicated figure the API and entity pages already report.

2026-07-02

Media Tone coverage expanded across the board. A rollup step was leaving many entities' computed tone unserved — their stories were scored, but the daily tone summary the API and entity pages read didn't reflect it. That rollup now folds in every scored story, so roughly 11,000 more entities (well-covered and lightly-covered alike) show their real Media Tone, and thin/single-source entities went from ~42% to ~65% tone coverage.

Honest tone availability: an entity whose only coverage was too thin to score (single-source stories with no extractable evidence) previously reported tone as "available" with zero scored stories. It now correctly reports tone as not-available, so "available" always means there is at least one scored story behind the number.

2026-07-01

Entity pages now resolve consistently to the canonical entity. A person or company profile could occasionally split into a near-duplicate keyed to a misspelled or translated variant of the name (e.g. “Donal Trump” vs “Donald Trump”): that variant page showed near-zero stories / articles / events and an empty 30-day activity pulse, even though the Media Tone panel — resolved separately — showed the entity's full coverage. Every section now keys off the same canonical entity, so the header counts, activity pulse, linked stories / events, connected entities, and tone all agree — and a variant-spelling URL 301-redirects to the canonical entity page.

Entity pages for lightly-covered figures no longer show an empty story list. When an entity has real, Wikipedia-linked coverage but too little to be promoted into our resolved entity registry (e.g. a founder named in a handful of funding stories), the header counted the stories while the Linked Stories panel showed “none” — a mismatch. The linked-stories list now draws those stories from the same derived Story layer as the counts, so the two agree.

Media Tone now covers lightly-covered entities. Tone was previously computed only for entities with enough multi-source coverage, so a figure who appears mostly in single-source stories (many founders, regional officials, and other niche entities) showed an empty Media Tone panel even when the rest of the profile had data. Tone is now computed across all of a lightly-covered entity's stories — including single-source ones, which are often all it has — so these profiles carry a mean tone, risk, and confidence like any other, with a confidence score that honestly reflects the thinner evidence. Well-covered entities are unchanged: their single-source stories are still excluded so their aggregates stay clean.

2026-06-30

SEC Filings resolve is now fuzzy and cross-source. Resolving a company by name returns a ranked list of close matches (not a single guess), and a common name now finds the real filer — e.g. “SpaceX” resolves to SPACE EXPLORATION TECHNOLOGIES CORP (CIK 1181412) via the entity graph, instead of a namesake investment fund. Resolved companies, filers, 8-K counterparties, and material-event entities now carry the link to jump straight to their GDELT Cloud entity page.

API Playground (early-access SEC surface): result cards now showcase the structured data. Material Events lead with the extracted headline, event-type, SEC item, counterparties, deal value, and a confidence score; filer profiles show a business description with segments and products; and Resolve shows the ranked candidate list with cross-source entity links.

Macro API: the Series catalog gained a seasonal-adjustment filter, and the Releases rollup is now filterable by originating agency or a release-name search (previously a fixed, unfilterable list).

2026-06-29

Entity & event profiles no longer repeat a story: when several near-duplicate clusters share an identical headline on the same day, the recent-stories list now shows it once (keeping the highest-coverage cluster). The same headline on a different day, and merely similar headlines, are preserved.

Entity list counts now match the entity profile. Per-entity article / story / event counts in GET /api/v2/entities come from our resolved entity layer — the same source the single-entity endpoint uses — so the list and the profile always agree (previously the list read a pre-resolution layer that could over- or under-count).

Filtered entity counts are now labelled. When you filter entities by an event category (e.g. Protests) or attribute (e.g. civilian-targeting), the counts are scoped to that filter and the response flags this with a metrics_scope field, so a small “2 stories” reads correctly as “2 protest-linked stories” rather than looking broken.

Better ranking for filtered entity queries: filtered entity lists now rank by how specific an entity is to the filter rather than by raw mention volume, so “protest-linked organizations” surfaces protest-specific bodies (parties, unions, committees) instead of being dominated by ubiquitous entities that co-occur with everything.

API Playground: the Code view (curl / Python / Node) now renders the exact public API call — path parameters such as entity_id are placed in the URL path, so the snippet is copy-paste runnable — and every record/list endpoint now defaults to 10 results.

2026-06-28

Coming soon (early-access preview, admin-only for now): a material-events feed at GET /api/v2/filings/events — dated 8-K corporate events (mergers and acquisitions, material agreements, executive changes, bankruptcies, delistings, impairments) extracted from 8-K bodies, with named counterparties resolved into the entity spine so a filed event joins the live Events/Stories/Entities graph on entity and date. Filter by company (cik), event_type, or a headline search over a ≤30-day window.

This SEC Filings surface is being finalized and is not yet generally available — it returns 403 ADMIN_REQUIRED for other API keys while we ready it for all plans. We'll announce general availability here when it ships.

8-K coverage was also improved: the pipeline now scans the newest filings first with a higher daily cap, so material events surface sooner and more completely.

2026-06-28

Event recall (methodology): the events pipeline now captures incidents reported a day after they occurred or across a timezone boundary — common for diplomacy (state visits, agreement signings, leaders' remarks) and late-breaking conflict updates that previously fell outside the single processing day and went uncoded.

Events are dated to the day the action actually occurred, which can be the prior UTC day, so date filters and timelines reflect true occurrence dates. You may notice more coded events overall and some dated to the previous day. De-duplication runs across adjacent days, so an incident reported over two days remains a single event.

Entity coverage counts (fix): per-entity article / story / event counts now consistently reflect GDELT Cloud's own Stories and Events over the selected window. Previously a high-profile entity surfaced by name search could show a large article count next to 0 stories and 0 events — an inconsistency from mixing an all-time article figure with windowed linkage. All three counts now come from our resolved entity layer and are mutually consistent, so some entities will show smaller but accurate counts.

2026-06-26

Internal preview (admin-only): added maritime vessel-flow signals derived from public and commercial AIS vessel-tracking sources. The product exposes chokepoint transit activity across 11 maritime chokepoints (Hormuz, Bab-el-Mandeb, Malacca, Suez, Panama, and others), per-chokepoint dwell time and AIS-dark gaps, and last-known vessel positions and identity — vessels matched to Global Energy Monitor's LNG-carrier registry.

These are derived signals — transit counts, dwell, gaps, and last-known positions — not a raw position firehose or full track history. There is no historical backfill: maritime signals accrue from launch forward only. Coverage is terrestrial-AIS, so open-ocean segments outside shore-station range are not observed.

Macro (FRED) preview: broadened the curated economic-series catalog to ~90 series spanning national accounts, prices/inflation, labor, rates/yields, money/credit, trade, housing, business activity, consumer, and commodities/markets. The catalog is now fully discoverable — browse the live list at GET /api/v2/macro/series (call with no filters to enumerate everything), see the grouped reference at docs.gdeltcloud.com/api-reference/macro-series-catalog, and unknown series_id responses now point to both.

2026-06-25

Internal preview (admin-only): added SEC EDGAR filings to the V2 API under /api/v2/filings — list and summarize filings by company, form type, and date; a per-filer profile with recent filings and XBRL financial highlights; an XBRL facts slice; and name/ticker resolution into the entity registry. EDGAR content is public domain; cite the SEC as source.

Corporate relationships (subsidiaries, suppliers, customers, jurisdictions) are surfaced from filing text through our proprietary AI pipeline and resolved into the entity registry as typed, traversable edges, so a news event can be traced to the public companies that disclosed exposure.

MCP: a new progressive-discovery tool category (filings) surfaces the above to the research agent; admin-only while in preview.

Internal preview (admin-only): added official U.S. economic time series (Federal Reserve / FRED and originating agencies) to the V2 API under /api/v2/macro — a searchable series catalog, point-in-time (ALFRED) observations with an as-of vintage parameter so a query never looks ahead, per-series detail, and an agency/release rollup. Third-party-copyrighted series (e.g. S&P, ICE) are never served, and macro text never enters any embedding corpus. This product uses data from the Federal Reserve Bank of St. Louis (FRED) but is not endorsed or certified by it.

2026-06-24

Admin billing now reports recurring revenue as an explicit matrix: effective MRR, effective ARR, current-month paid invoice cash, and year-to-date paid invoice cash, each split across monthly-billed and annual-billed subscriptions.

Admin outreach queues now exclude live paying customers even when cached prospect rows are stale, add "other" and "already paying" dispositions, and separate To-Do and Done loading so admins can reach actionable prospects faster.

Admin user pages now surface plan source, access, overrides, and current-period usage together, and Brief access now consistently honors frozen billing state across current and retained Brief routes.

2026-06-22

Redesigned the homepage and public navigation for a calmer, more enterprise feel: a focused hero with a subtle cursor-reactive "world-state" background (events drifting, stories clustering, fresh signals pulsing), the live-data video demoted to a small framed accent, and the per-surface deep dives (API, MCP, Agent, Alerts, Briefs) moved into structured Product / Solutions / Resources menus. Existing pages keep their URLs.

Added a "See it live" section previewing the distinctive surfaces — Event Taxonomy, Early Signals, vs Raw GDELT, Briefs Showcase, and the interactive Demo — each with a small data-literal animation (media-tone meter, share-of-voice bars, event-to-story clustering, an early-signal sparkline). All motion respects the reduced-motion preference.

Introduced an opt-in customer logo strip on the homepage for subscribing commercial customers. It is off by default and admin-curated: each customer is added explicitly and has an individual on/off switch for removal requests, consistent with the paid-customer logo-use clause in the Terms.

2026-06-20

Entity resolution now recognizes former names and common acronyms for renamed organizations. Searching a prior identity — e.g. "NARAL" or "NARAL Pro-Choice America" — now resolves to the current canonical entity (Reproductive Freedom for All) as a strong, exact match instead of returning unrelated typo neighbors. This flows through the resolver, Entity Tone, and Share of Voice.

Seeded an operator-maintained alias layer for a starter set of renamed advocacy, political, and corporate organizations, with optional enrichment from Wikipedia redirect titles and Wikidata also-known-as names. Former corporate names (e.g. "Facebook, Inc.") resolve to the current entity while staying distinct from same-named product entities.

Stories and Events now carry a per-card source-language breakdown (e.g. EN 6 · AR 2 · ZH 1) and accept a "Source language" filter, so you can isolate Arabic, Chinese, or any source language across the story and event feeds.

Entity profile pages now include a Media Tone preview: the mean tone of press coverage toward the entity over the last 30 days (−100 critical to +100 favorable), with scored-story and article counts, a reputational-risk read, model confidence, a daily tone-trend sparkline, and coverage languages. It measures how the press covers the entity — not public opinion or polling — and missing coverage shows as unavailable, not neutral.

The Data Status page now reports the distribution of source languages across ingested coverage (24-hour and 30-day windows).

Regional source coverage was expanded and hardened: restored WAF-blocked Gulf/Levant feeds, added Global Times and Argaam (Gulf energy/markets) plus additional Arabic outlets, and retired confirmed-dead frozen feeds — improving Arabic and Chinese hard-news flow into Stories, Events, and Entities.

2026-06-19

Chinese-language coverage is substantially expanded: the native-source fetcher now resolves each article's title from its page (og:title/<title>) instead of relying on homepage link text, restoring fresh hard-news flow (politics/economy/diplomacy) from People's Daily, Guangming Daily, Yicai, Eastmoney, 21st Century Business Herald, China Daily, CCTV, and Beijing News into Stories, Events, Entities, and Entity Tone. Feed-less or low-signal sources (the Xinhua homepage, Guancha, Securities Times, China Economic Net) were retired in favor of GDELT translingual, China News Service, and CGTN coverage.

Native Arabic/Chinese regional-source articles now contribute article images, provenance, source-language metadata, and gate-spotted entities into the existing V2 Stories, Events, Entities, Entity Tone, and Share of Voice surfaces.

The hourly product pipeline now turns native gate entities into article mentions, resolves likely Wikipedia pages with a GPT-5.4-nano query step plus the Wikipedia API, and carries active non-Wiki `llm:*` entities through V2 entity refs and entity detail responses.

The Ingest Command Center regional-coverage panel now tracks native URLs, sources, domains, product articles, Stories, Events, and visible entity-link contribution over the rolling 24-hour window.

Public story/entity image enrichment now gracefully skips optional native-source image columns until the ClickHouse migration is applied, and the public Briefs showcase is cache-backed while still refreshing immediately after admin curation or share/revoke actions.

Public Story, Event, Entity, and shared Brief detail pages now use route-level ISR again while preserving client-side page-view tracking and hourly data freshness.

Early Signal public pages now publish from slimmer snapshot-backed payloads and avoid deploy-time monitor/run enumeration, making scheduled marketing scorecards more reliable while preserving per-run archive links.

2026-06-18

Native Arabic/Chinese source ingest is now available behind eval-safe schema routing, with raw native-source audit tables, article provenance bridging into `gdelt_cloud`, and a local HTTP e2e acceptance script for V2 stories, events, entities, Entity Tone, and Share of Voice.

Public Data Status, demo, and GDELT comparison pages now use tighter cache lanes, route prewarming, and smaller first-load client islands so customers see faster public-page loads while hourly data freshness is preserved.

Data Status now serves a tagged hourly snapshot and lazy-loads detailed metric distributions from a cached public endpoint; fixed-window demo pages avoid unnecessary sub-hour warehouse refreshes.

Entity search restores all-time Wikipedia-linked recall for People and Organizations: explicit entity-name searches now use the GEG Wikipedia lookup alongside recent activity tables, and Entity Tone / Share of Voice resolve those searches to the same canonical wiki IDs.

2026-06-17

Admin-granted plan access now applies to the user's personal organization, mirrors back to the owner profile, and preserves Stripe billing state so demo grants unlock runtime features such as Briefs, API, and MCP without creating duplicate subscription drift.

Payment safeguards now continue to honor active, past-due, and unpaid Stripe subscriptions even when an admin plan grant is masking the visible plan source.

2026-06-16

Entity analytics search is now shared across the new entity registry, entity resolution, the legacy Entities list, and risk/exposure lookup paths, with fuzzy alias, short-name prefix, acronym, typo, token-set, and semantic-vector tiers where embeddings are available.

Share of Voice denominators that include query text now use semantic cluster search and return explicit denominator metadata: search mode, score floor, candidate cap, truncation status, and separate numerator/denominator counts.

Entity Tone evidence is easier to audit: samples are collapsible, story links use readable Story titles, article titles are cleaned, source domains are clearer, and entity names are shown separately from evidence titles.

Admins now have an Entity Universe overview for registry size, alias/vector coverage, resolved-story coverage, tone-scored coverage, date ranges, and non-Wiki extraction status. Risk and Exposure pages now include helpful defaults, scenario chips, and fuzzy counterparty resolution.

Energy Data now targets the May 2026 GEM coal mine and ownership releases and adds owner lookup endpoints plus MCP tools, so asset portfolios can be discovered from canonical GEM ownership entities before drilling into assets or exposure.

Automatic QU overage attempts now retain local invoice diagnostics for failed Stripe paths, including idempotency key, retry index, payment-method source, invoice IDs, and whether stranded open invoices were voided.

2026-06-15

Entity Tone and Share of Voice are now additive beta API surfaces: cached entity-tone reads when side-table scores exist, optional evidence samples for review, denominator-explicit share-of-voice responses, plot-ready SOV timelines, and durable beta queue rows for on-demand scoring requests.

The tone methodology separates media tone from reputational risk, treats missing evidence as unavailable rather than neutral, and keeps scoring output in side tables instead of changing the existing ingest workflow. Admin-account dogfood pages now expose Entity Tone and Share of Voice with API View.

The V2 entity-tone scorer now supports high-volume concurrent processing with a per-run Tavily fallback budget, so hourly dogfood ingest can cover thousands of queued entity-story cases without making web extraction the critical path.

2026-06-11

Bonus query-unit top-ups and time-boxed plan trials are now explicit offers: the email includes a Claim button, and nothing is applied to your account until you accept. Offer links expire after a set window, and you can always reply to the email to discuss or request something different.

2026-06-10

Query Unit grants and time-boxed limit bumps are now fully honored against the per-period usage counter: a granted account can use its entire grant before reaching its limit, where previously the effective ceiling could narrow as the grant was drawn down.

Automatic overage now measures the chargeable amount against the full free allowance — base limit, already-paid overage, and any active grant or limit bump — so granted or bonus Query Units, and headroom from a bump that has since reverted, are never billed as overage.

2026-06-08

V2 Events now support canonical metric range filters on list and summary endpoints, including significance, confidence, Goldstein scale/severity, magnitude, systemic importance, propagation potential, and market sensitivity.

The Events UI, API Playground, OpenAPI reference, docs, and MCP search/summary tools now expose the same metric filter contract, with CAMEO+ and Goldstein applicability documented.

The API Playground now includes dedicated V2 Event Summary, Story Summary, and Energy Summary tools with authenticated execution, presets, snippets, and rendered summary rows.

Data Status now shows rolling 24-hour and 7-day distributions for Event metrics using partition-pruned ClickHouse queries.

2026-06-07

Organization settings now refresh correctly when switching active organizations, so the organization name, slug, domain, member-key setting, billing panels, and usage panels stay aligned with the selected workspace.

Brief-originated tool usage now records 0 Query Units. Briefs remain metered in Brief Units, and future Brief usage rows no longer appear at the hosted research-agent QU rate.

Admin usage monitoring now groups feature usage into product surfaces such as V2 API, MCP, Agent, Brief, and Web App, with paginated feature tables plus member and API-key drilldowns and CSV exports.

Organization plan enforcement has been tightened for Alerts and Briefs: active-organization plan features, limits, Brief Units, purchased credits, schedules, and API-key usage now stay scoped to the workspace that owns the request.

Admins can now add user- or organization-specific entitlement overrides for plan-controlled quotas, permissions, feature flags, Brief limits, API rate limits, and overage settings without changing the account's current plan.

Admins can also issue one-time QU/BU grants with optional expirations and save custom user- or plan-level billing discounts that are applied during subscription checkout or plan changes.

Google sign-in now keeps signup-only welcome and founder follow-up emails out of returning-user sign-ins; signup emails are owned by the initial auth.users insert path and remain idempotent.

2026-06-06

Terms now include a limited customer identification/logo-use clause for active paid customers only, and paid plan cards link directly to that section so the subscription flow is explicit.

Admin Growth now reports one fixed UTC week-to-date comparison against the previous Monday-aligned window, with Gross Monthly Income separated from Net MRR and canceling, at-risk, and churned/lost states broken out.

Admin user-related list pages now default to 20 rows with pagination and simple case-insensitive email substring search where relevant, reducing slow initial admin loads.

Attio CRM sync now mirrors new signups and plan-status changes into People records using the imported email/name/account-created/plan/plan-mode mapping, with local development guarded to TEST-marked records only.

Attio People sync now supports validator-first daily usage rollups for recent activity, QU, and Brief Units, gated behind ATTIO_USAGE_METRICS_ENABLED.

2026-06-04

Monitoring Briefs now lead with an Event Timeline in the body of the report — a horizontal, date-anchored chronology of the GDELT Cloud Events the brief cites (not just a short list), matching the Early Signals timeline. Hover any event for its date, category, and significance.

New “Relevant entities” section. Each brief now surfaces the load-bearing People and Organizations driving the question, with their window-over-window article/story/event activity and a one-line role — drawn from the GDELT Cloud entity graph the research traversed.

Maritime briefs now pull a temporary, open-web AIS picture (vessel diversions, AIS gaps, port congestion from sources like MarineTraffic and Lloyd's List), clearly labeled as open-web-derived rather than a live feed, until a dedicated AIS feed is wired in.

The Brief library drawer now groups every run of a Brief under one definition: open an entry to see its runs split into Manual and Scheduled, with shared and searchable status shown at a glance. Schedules and their runs now live in one place.

Consistency fix: the “What changed”, comparison-windows, and benchmark visuals now derive from a single source as the Lookback/Baseline columns, so the chart and the table can no longer disagree.

Research now opens broad before narrowing — a wide discovery pass surfaces the actors, angles, and second-order threads up front, so briefs miss less relevant context from searching too narrowly too soon.

Brief polish: entity cards now show each actor's Wikipedia image (the same one on their Entity page), Event Timeline cards lift to the front on hover so an overlapped event stays readable, and official-source and article cards now link out to their source.

Prediction-market readings are now self-consistent: when a brief's quoted probability disagrees with the market's own captured history (for example, a long-horizon contract's odds mistaken for a near-term one), the headline is reconciled to the live series — so the number can no longer contradict the sparkline shown beside it.

2026-06-03

Organizations are here. Every account now belongs to an organization — your existing account is grandfathered into a personal organization with nothing to change. Create a company organization to invite teammates and share one subscription, API keys, and pooled usage. Invite by email; people who already have a GDELT Cloud account are linked automatically, and there's an organization switcher in account settings.

Owner / Admin / Member roles. Owners and admins manage members, API keys, and billing; members use the product and see organization usage. API keys are organization-scoped, with one-click rotation, last-used timestamps, and an audit-lite activity log. Members can create their own organization keys by default; an admin can turn that off, and a member's keys are automatically revoked when they leave the organization.

Annual billing. Plans can be billed monthly or annually (two months free by default). The pricing and subscription pages have a Monthly/Annual toggle that defaults to Annual; annual plans show the effective monthly price ("billed annually") so it's easy to compare with monthly.

Team features are now a plan-tier capability. Inviting teammates to a company organization — sharing one subscription, API keys, and pooled usage — is available on plans that include teams (set per plan by admins). Solo personal workspaces are unaffected; organizations on a plan without teams see an upgrade prompt instead of an invite.

Clearer, consistent usage reporting. Usage is pooled and reported per organization, broken down by feature, member, and API key — including Briefs. Plan limits, Query-Unit usage, and overage now follow your active organization everywhere — the web app, API Playground, alerts, and MCP — so personal and organization usage never mix. A color-coded indicator at the top of every page shows which workspace you're in, and admins can export usage to CSV.

Monitoring Briefs are now in Beta for everyone. The Briefs workspace is available on every account; plans that don't include Briefs see a preview with an upgrade path. Brief access follows your active organization's plan.

Google sign-in reliability improved: OAuth sessions now preserve safe post-login destinations, handle expired PKCE verifier state with a friendly retry path, and pin Supabase auth dependencies so installs no longer drift underneath the login flow.

2026-06-02

Monitoring Briefs can now be published to public search. From a Brief's page, opt in with “Publish to search” to get a stable, indexable public page at /briefs/published/… with its own preview card and structured data. Publishing is off by default and set per Brief; the existing unguessable share links stay private and are never indexed.

New discovery pages help teams find GDELT Cloud for what they actually search for: a comparison hub (/compare — including vs. raw GDELT, news APIs, Dataminr, and AlphaSense) and an Industries section (/industries) for maritime, supply-chain, energy-infrastructure, country-risk, OSINT, and finance/macro teams.

Added a homepage FAQ and refreshed site metadata and structured data (organization, software, pricing/offers, product, article, and FAQ schema) so GDELT Cloud shows up more clearly and richly in search results.

2026-06-01

Detailed Briefs are now a plan-controlled tier. Briefs are metered in Brief Units (BU): a skim/standard Brief costs 1 BU, and a Detailed Brief — which investigates first, second, and third-order effects with far more evidence — costs a Brief-Unit amount set per plan. Admins choose which plans can run Detailed Briefs and their BU cost; the pricing page now explains BU alongside QU.

New Monitoring Briefs showcase at /briefs-showcase featuring real, live Briefs. Admins curate the lineup in the Briefs admin page by pasting public share links and uploading a screenshot of each Brief's web view to use as the card's header image.

Any Brief can now be re-run on demand with “Run Now” — it generates a fresh Brief from the same inputs (one-off or scheduled) and keeps the prior runs. Re-runs are grouped into a run history: the Briefs library shows one entry per Brief with a runs list, and each Brief page has a run switcher to move between snapshots. The Briefs library and detail pages also load markedly faster.

Admin Growth, Activity, and user-detail pages now use lighter aggregate queries and user-scoped reads, and public/auth pages skip unnecessary session work before rendering. Admins should see faster dashboard loads and fewer transient enrichment errors during upstream Wikipedia slowdowns.

2026-05-31

Monitoring Briefs are now available: a short, source-backed intelligence memo that answers what changed, why it matters, what evidence supports it, and what to watch next — generated from structured events, clustered stories, mapped evidence, market context, and linked entities, with a full source appendix.

Briefs are metered separately from Query Units and never draw down your QU pool. Each plan includes a monthly Brief allotment; additional Briefs are purchased as never-expiring credits. A new Briefs scenario in the pricing calculator estimates the right plan for your monthly volume.

Briefs can be created, listed, and fetched over the REST API (`/api/v2/briefs`) and the MCP server for plans with Briefs enabled. Creation returns immediately and runs in the background (briefs take ~5–10 minutes); each brief can optionally expose a public share link.

2026-05-30

V2 Event taxonomy subcategory filters now use stable CAMEO+ event codes, so filters such as `category=TECHNOLOGY&subcategory=TE01` work consistently across Events, Stories, Entities, and the API Playground.

CAMEO+ response subcategory labels are now normalized to canonical codebook labels such as `TE01 · AI Capability Event`, while older label-style query values remain accepted for compatibility.

2026-05-29

Plan Query Unit (QU) limits are now enforced atomically. Previously, requests issued concurrently right at a plan's monthly QU limit could each pass the limit check before any was recorded, letting usage overshoot the cap by a small amount. Enforcement now reserves QU in a single atomic step, so the limit holds exactly and surplus concurrent requests receive a 429 QUOTA_EXCEEDED response.

Closed a billing-bypass vector: the internal 'no-charge' marker header used by the MCP proxy is now honoured only when accompanied by the trusted internal usage secret, so external API callers can no longer set it to zero out their own usage.

Faster public entity, event, and story pages via a date-aware cache: content for the current UTC day stays on the hourly refresh, while event and story pages from previous days — which no longer change — are cached longer and served without re-querying the warehouse on every request. Repeat and long-tail crawler traffic no longer triggers an hourly re-query. No API response shapes change.

2026-05-27

V2 list and summary responses now include an applied_filters block — a top-level peer of pagination — echoing the resolved filter values the SQL actually used (post region/continent expansion, post CSV split) plus an `ignored` map of any URL params the endpoint didn't recognize. Lets callers self-detect when a filter quietly fell through.

Every multi-value filter on the GDELT Cloud and Energy MCP tools (search_events, summarize_events, search_stories, summarize_stories, search_entities, energy_search_assets, energy_summarize_assets, energy_assets_by_owner) now accepts a list of values (country=['United States','Vietnam'], fuel=['solar','wind'], etc.). The V2 URL contract is unchanged — country=USA,VNM still works.

search_entities `search` description clarified to lead with the param name and explain the exact-match ranking, removing the wording that led some agents to invent a non-existent `name` kwarg.

MCP tool-result widgets now use the Prefab renderer as the canonical MCP Apps path, with ChatGPT compatibility metadata retained on the same renderer URI.

GDELT Cloud, energy, prediction market, macro finance, and web research MCP calls now carry richer structured widget payloads plus raw-data fallbacks for the Agent UI Artifacts drawer.

2026-05-26

V2 Events, Stories, Entities, and API Playground now default to the exact past 24 hours, guard 30-day API windows in the UI, and show friendlier validation errors.

Category is now the primary Event taxonomy filter across UI, API docs, and MCP; event_family remains backwards compatible but is deprecated. Subcategory filters now require their parent category and return scoped recovery options.

Entities gained linked Event taxonomy filters, and recent sorting for Stories and Entities now follows actual latest observed/update time.

Conflict Event civilian_targeting is now returned on V2 Event cards and exposed as a filter across Events, Stories, Entities, API Playground, docs, and MCP.

2026-05-23

Google sign-in added. New and returning users can now use the 'Continue with Google' button on the login and signup pages alongside the existing email/password flow.

/data-status V2 API latency chart fixed: query was silently capped by PostgREST max-rows and only rendered the oldest few days in the 30-day window. Now aggregates p50/p95 in Postgres and filters to /api/v2/* API-key traffic specifically.

Subprocessor descriptions clarified: Global Energy Monitor data is loaded offline from GEM, not via BigQuery; LangSmith is primarily our agent runtime host (tracing secondary); OpenAI is used for both LLM completions and embedding generation; Tavily is used for web search and content extraction.

Methodology page latency estimate corrected to ~15 minutes (the duration of the ingest pipeline), down from the earlier ~1 hour figure.

2026-05-22

Trust Center launched. New pages cover security posture, subprocessors, methodology, and this changelog. Privacy policy augmented with explicit AI-training and agent-trace language.

Wikipedia entity fetch timeouts handled more gracefully during entity enrichment runs.

Demo snapshots stabilised: snapshot files now carry a required refreshed_at timestamp; demos directory ignore rule fixed in .gitignore.

Demo pages launched at /demo for product walkthroughs.

2026-05-08

Privacy Policy, Terms of Service, and Acceptable Use policy rewritten in plain language and consolidated under a shared Trust Page layout.

Spot something off?

If a release note is incorrect or a behaviour change is missing, let us know.