# VerifiedCarrier CO2 — EU Ship Emissions League Tables (`atlas-data/verified-carrier-co2`) Actor

EU shipping CO2 league tables & audit-ready Scope 3 exports from official EMSA THETIS-MRV publications. Ranks ships and carriers by verified carbon-intensity within ship-type peer groups, with percentiles, coverage flags, watchlists and provenance. Analytics only - not compliance advice.

- **URL**: https://apify.com/atlas-data/verified-carrier-co2.md
- **Developed by:** [Atlas](https://apify.com/atlas-data) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## VerifiedCarrier CO2 — EU Ship Emissions League Tables (EMSA THETIS-MRV)

Audit-ready **EU shipping CO₂ league tables** and **Scope 3 export rows** built strictly from the
official EMSA **THETIS-MRV public publication of information** (Regulation (EU) 2015/757, Art. 21).
The Actor downloads the official per-period spreadsheet publication, normalizes the verified
carbon-intensity indicators into like-for-like ship-type peer groups, ranks **ships and carriers**
with percentile context, flags low-coverage fleets, and emits provenance-linked records that cite
the exact publication version and generation date behind every figure.

> **Informational analytics only.** Outputs are NOT compliance, legal, regulatory, scientific or
> financial advice, are not official figures, and must be verified against the official source
> before any regulatory use. Coverage reflects the EU MRV scope only (voyages touching EU/EEA
> ports), which limits comparability with global activity.

### Who it is for

- Sustainability/ESG managers preparing CSRD-aligned Scope 3 (Cat. 4/9) inventories who need
  officially sourced, citable carrier carbon-intensity figures instead of carrier marketing sheets.
- Freight procurement teams benchmarking carriers during tenders on like-for-like peer groups.
- Consultants and auditors needing reproducible exports with publication-version provenance.

### What one run produces

| Record type       | Meaning |
|-------------------|---------|
| `run_summary`     | Always first: mode, metric, periods processed with official version/generation-date fingerprints, coverage counts, notes, disclaimers. |
| `carrier_rank`    | Carrier league table per ship-type peer group: CO₂-weighted mean intensity, fleet size, ships ranked vs missing-indicator, rank + percentile. Emitted where EMSA publishes company attribution (FY2024+). |
| `ship_rank`       | Ship league rows within peer groups: published indicator value, total verified CO₂, technical efficiency label, rank + percentile. |
| `period_update`   | Incremental mode: emitted when EMSA republishes a period under a new version. |

Every ranked record carries `provenance` (source URLs, official disclaimer, retrieval timestamp),
`periodVersion`, and `generationDate`, so any figure in a customer's audit file can be traced to
the exact official publication it came from.

#### Methodology (documented, deterministic)

1. **Source.** The official listing endpoint enumerates the published spreadsheet documents; the
   newest version per requested reporting period is downloaded (XLSX). No HTML scraping, no login,
   no circumvention — this is the portal's own advertised export channel.
2. **Normalization.** Columns are mapped by normalized header text (never fixed positions), so
   pre-ETS ("Annual average CO₂ emissions per transport work …") and post-ETS layouts both resolve.
   Published sentinel strings (`"N/A"`, `"Division by zero!"`) count as *missing values*, never zero.
3. **Peer groups.** Ships compete only within their own ship type. Ranks ascend by the selected
   verified indicator (rank 1 = lowest intensity). `percentileWorseThan` = share of peers with
   equal-or-worse intensity (0 = cleanest).
4. **Carrier aggregation** (FY2024+). Members of a company inside a peer group yield a CO₂-weighted
   mean indicator plus a simple median. Companies with fewer than `minimumCarrierFleetSize`
   rankable ships stay visible but receive **no rank** (visible de-ranking instead of misleading
   small-sample comparisons).
5. **Coverage honesty.** Ships without a usable published indicator are counted
   (`shipsMissingIndicator`, `missingMetricValues`) and never silently compared.

### Input (see input schema for all options)

```json
{
  "mode": "full",
  "reportingPeriods": [2024],
  "metric": "co2_per_transport_work_mass",
  "topKPerLeagueTable": 25,
  "minimumCarrierFleetSize": 5,
  "companyWatchlist": ["Maersk", "CMA SHIPS"]
}
```

- `reportingPeriods`: up to 3 official periods per run (2018–2025 as published).
- `metric`: mass / dwt / pax / freight / volume transport-work intensities, or CO₂-per-distance.
- `companyWatchlist`: matched companies/ships are always emitted and flagged
  `watchlistMatch=true` — even beyond the top-K cut.
- `mode: incremental` re-downloads nothing while the official publication fingerprint is
  unchanged; a republished period emits `period_update` plus fresh tables.

A default run downloads one ~9 MB official workbook and finishes comfortably within minutes;
incremental unchanged runs make exactly one small API call. Incremental state persists in the
**named** key-value store `verified-carrier-co2-state` (key `state-v1`), which survives across
runs — the platform-scoped default store is wiped per run by design.

### Honest scope limits

- **Carrier rankings need FY2024+.** EMSA's public publication attributes an ISM company to each
  ship only from the FY2024 publication onwards; earlier periods get ship-level tables only. This
  is disclosed in every run summary rather than approximated.
- Partial-period publications (e.g. a running FY2025 file) are marked `partialPeriod: true`.
- Percentiles describe position within the EU MRV-reporting universe of that peer group — not
  global fleet efficiency.

### Attribution & terms

Data: © European Maritime Safety Agency (EMSA) THETIS-MRV public publication under Regulation (EU)
2015/757 Art. 21; data entered by companies and verified by accredited verifiers. The official
source disclaimer is embedded verbatim in every run summary. VerifiedCarrier CO2 is an independent
analytics Actor, not affiliated with EMSA or the European Commission. Source verification notes:
see `docs/SOURCE-VERIFICATION.md`.

### Development

```bash
npm install
npm run lint && npm run typecheck && npm run build
npm test                 # unit + integration + adversarial + schema tests
npm run test:smoke       # live-source smoke (hits real THETIS-MRV endpoints)
npm run smoke:local      # full local Actor run against the real source
```

Node.js 20+. Apache-licensed SheetJS is used for XLSX parsing; all other logic is local to `src/`.

# Actor input Schema

## `mode` (type: `string`):

incremental: downloads and parses an official publication only when its version/generation date changed since the last run. full: always rebuilds from the current official file.

## `reportingPeriods` (type: `array`):

Official THETIS-MRV reporting periods to process (max 3 per run; each requires downloading one official spreadsheet). Carrier-level rankings exist only for periods from 2024 onwards, when EMSA began publishing the responsible company in the public files.

## `metric` (type: `string`):

Which officially published annual-average intensity indicator ships and carriers are ranked by within like-for-like peer groups. Lower is better (rank 1 = lowest verified intensity in the peer group).

## `shipTypeFilter` (type: `array`):

Restrict output to these official ship types (peer groups). Leave empty to include every type.

## `topKPerLeagueTable` (type: `integer`):

How many ranked rows to emit per peer-group table. Watchlisted companies/ships are always emitted in addition, flagged with watchlistMatch=true.

## `minimumCarrierFleetSize` (type: `integer`):

Carriers need at least this many rankable ships inside a peer group to receive a carrier rank/percentile. Smaller fleets still appear with coverage counts but without a rank (visible de-ranking instead of misleading small-sample comparisons).

## `includeCarrierLeagueTable` (type: `boolean`):

Emit carrier\_rank records (companies aggregated within ship-type peer groups). Available only where EMSA publishes company attribution (FY2024+).

## `includeShipLeagueTable` (type: `boolean`):

Emit ship\_rank records (individual ships ranked within their ship-type peer group).

## `companyWatchlist` (type: `array`):

Case-insensitive substrings matched against published company names (or exact numeric IMO/company numbers), e.g. \["Maersk", "CMA SHIPS", "5112991"]. Matched carriers and ships are always included in the output and flagged watchlistMatch=true.

## Actor input object example

```json
{
  "mode": "full",
  "reportingPeriods": [
    "2024"
  ],
  "metric": "co2_per_transport_work_mass",
  "shipTypeFilter": [],
  "topKPerLeagueTable": 25,
  "minimumCarrierFleetSize": 5,
  "includeCarrierLeagueTable": true,
  "includeShipLeagueTable": true,
  "companyWatchlist": [
    "Maersk"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `state` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "full",
    "reportingPeriods": [
        "2024"
    ],
    "metric": "co2_per_transport_work_mass",
    "shipTypeFilter": [],
    "topKPerLeagueTable": 25,
    "minimumCarrierFleetSize": 5,
    "includeCarrierLeagueTable": true,
    "includeShipLeagueTable": true,
    "companyWatchlist": [
        "Maersk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("atlas-data/verified-carrier-co2").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "full",
    "reportingPeriods": ["2024"],
    "metric": "co2_per_transport_work_mass",
    "shipTypeFilter": [],
    "topKPerLeagueTable": 25,
    "minimumCarrierFleetSize": 5,
    "includeCarrierLeagueTable": True,
    "includeShipLeagueTable": True,
    "companyWatchlist": ["Maersk"],
}

# Run the Actor and wait for it to finish
run = client.actor("atlas-data/verified-carrier-co2").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "full",
  "reportingPeriods": [
    "2024"
  ],
  "metric": "co2_per_transport_work_mass",
  "shipTypeFilter": [],
  "topKPerLeagueTable": 25,
  "minimumCarrierFleetSize": 5,
  "includeCarrierLeagueTable": true,
  "includeShipLeagueTable": true,
  "companyWatchlist": [
    "Maersk"
  ]
}' |
apify call atlas-data/verified-carrier-co2 --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,atlas-data/verified-carrier-co2"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/WcVOR3mhE8lwGc4el/builds/K2mNs8opo5IsiIf4O/openapi.json
