# SNCF Train Ticket & Connection Scraper (`muhammadafzal/sncf-train-ticket-connection-scraper`) Actor

Scrape SNCF Connect train connections, departure and arrival times, journey duration, direct or connecting status, operators, displayed ticket prices, fare classes, seat-count hints, and onboard services.

- **URL**: https://apify.com/muhammadafzal/sncf-train-ticket-connection-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Travel, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 sncf train connections

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## 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

## SNCF Train Ticket & Connection Scraper

Search the public SNCF Connect booking flow and export one structured record per train connection. The Actor is designed for travel planners, price-watch dashboards, route research, and AI agents that need current departure and arrival times, journey duration, direct/connecting status, displayed fares, train operators, and onboard services.

### What it extracts

Each dataset item represents one SNCF Connect result card:

| Field | Description |
| --- | --- |
| `origin`, `destination` | Station labels shown by SNCF Connect |
| `departureTime`, `arrivalTime` | ISO timestamps in `Europe/Paris` |
| `durationMinutes` | Journey duration when displayed |
| `direct`, `changes` | Direct/connection interpretation of the result card |
| `carrier`, `trainType` | Displayed operator and normalized family (`tgv-inoui`, `ouigo`, `ter`, `intercites`, or `eurostar`) |
| `lowestPrice`, `fares` | Displayed EUR prices by class, including “dès” and seat-count hints when present |
| `services` | Onboard services such as Wi-Fi, bar, or bicycle space |
| `sourceUrl`, `searchedAt` | Result page and retrieval timestamp |

Prices and availability are live snapshots displayed by SNCF Connect. They are not a booking, quote, inventory guarantee, or guarantee that every operator is returned.

### When to use it

Use it for a bounded one-way route search. Enter station names as SNCF Connect presents them; city names such as `Paris` and `Lyon` are also accepted and are resolved to the best matching station. Use `directOnly` or `trainType` for a narrower result set, `priceMode: "schedules"` when fare cards are not needed, and `maxResults` for a predictable budget.

The Actor does not log in, purchase tickets, access user bookings, solve CAPTCHAs, or bypass DataDome. It only reads the public booking flow. A challenged session is returned as a clear `BLOCKED` diagnostic with zero result charges.

### Input

```json
{
  "from": "Paris Gare de Lyon",
  "to": "Lyon Part-Dieu",
  "departureDate": "2026-09-11",
  "departureTime": "08:00",
  "directOnly": false,
  "trainType": "all",
  "priceMode": "prices",
  "maxResults": 5,
  "maxLoadMoreClicks": 1
}
```

`departureDate` defaults to tomorrow in `Europe/Paris`. `maxResults` accepts 1–50. `maxLoadMoreClicks` accepts 0–8. The default proxy configuration uses an Apify French residential session because SNCF Connect commonly applies DataDome to non-browser or datacenter traffic. Keep the proxy, browser, cookies, locale, and geography consistent for a run.

Console/API example:

```bash
apify call YOUR_USERNAME/sncf-train-ticket-connection-scraper \
  -p '{"from":"Paris Gare de Lyon","to":"Lyon Part-Dieu","departureTime":"08:00","maxResults":3}'
```

### Output example

```json
{
  "connectionId": "5d0a5f0e4c46a4c0c98b5e8d",
  "origin": "Paris - Gare De Lyon - Hall 1 & 2",
  "destination": "Lyon Part Dieu",
  "departureTime": "2026-09-11T08:00:00+02:00",
  "arrivalTime": "2026-09-11T09:56:00+02:00",
  "durationMinutes": 116,
  "changes": 0,
  "direct": true,
  "carrier": "TGV INOUI",
  "trainType": "tgv-inoui",
  "services": ["Wifi à bord", "Voiture bar"],
  "lowestPrice": 49,
  "currency": "EUR",
  "fares": [{"className":"second","price":49,"currency":"EUR","priceFrom":true,"availabilityText":null}],
  "searchedFrom": "Paris Gare de Lyon",
  "searchedTo": "Lyon Part-Dieu",
  "searchedAt": "2026-09-10T03:00:00.000Z",
  "source": "SNCF Connect",
  "sourceUrl": "https://www.sncf-connect.com/home/shop/results/outward"
}
```

Run diagnostics are written to the `OUTPUT` key-value record. Outcomes are `DATA`, `EMPTY`, `BLOCKED`, `REJECTED`, or `FAILED`. The Actor never adds an error object to the homogeneous connection dataset.

### Pay per event

| Event | Price |
| --- | ---: |
| SNCF search start | $0.035 per GB (2 GB default = $0.070) |
| `train-connection` | $0.012 per delivered connection |

The start event is synthetic and is never manually charged. A connection is pushed to the dataset before its result event is charged. `maxResults`, pagination, and Apify’s maximum-charge limit bound work and spend. The minimum allowed cap is $0.15 to leave room for the 2 GB start, one result, and browser/proxy usage; the default cap is $0.30.

### Reliability and compliance

The scraper uses a displayed Chromium session, a French residential route, bounded concurrency, short pagination, coherent browser signals, and session retirement for HTTP 403/429 or challenge responses. If SNCF changes its page structure, the Actor reports an explicit extraction diagnostic instead of fabricating records. Respect SNCF Connect’s terms, robots/access policies, fare display conditions, and applicable privacy and database-rights law. Do not use this Actor to automate purchasing or circumvent access controls.

### Support

For a reproducible issue, include the redacted input, run ID, outcome, and `OUTPUT` record. Do not include cookies, proxy URLs, account credentials, or other secrets.

# Actor input Schema

## `from` (type: `string`):

Use this for the SNCF departure station or city. Enter the public SNCF Connect label, for example `Paris Gare de Lyon`. This is not a street address.

## `to` (type: `string`):

Use this for the SNCF arrival station or city. Enter the public SNCF Connect label, for example `Lyon Part-Dieu`. It must differ from the departure.

## `departureDate` (type: `string`):

Use this to search a specific travel date in Europe/Paris. Format `YYYY-MM-DD`, for example `2026-09-11`. Omit it to use tomorrow; past dates are rejected.

## `departureTime` (type: `string`):

Use this to choose the hour from which SNCF results are requested. Format `HH:mm`, for example `08:00`. SNCF Connect currently applies hour-level selection.

## `directOnly` (type: `boolean`):

Use this to keep only results SNCF marks as direct. Default `false` also allows connecting journeys.

## `trainType` (type: `string`):

Use this to retain one displayed operator family after extraction. `all` keeps every train; filters include TGV INOUI, OUIGO, INTERCITÉS, TER, and Eurostar.

## `priceMode` (type: `string`):

Use `prices` for public fares displayed by SNCF Connect or `schedules` for timetable-only results. Prices are live snapshots, not quotes or booking guarantees.

## `maxResults` (type: `integer`):

Use this to cap delivered and charged connection records. Minimum 1, maximum 50, default 10. A smaller value gives a cheaper bounded run.

## `maxLoadMoreClicks` (type: `integer`):

Use this to bound SNCF's `next journeys` pagination. Range 0–8, default 2. It is a work cap, not a guarantee that more results exist.

## `proxyConfiguration` (type: `object`):

Use this when SNCF Connect requires a consistent network identity. The default is an Apify residential session in France because the public site uses DataDome. Do not use it to bypass CAPTCHAs or access controls.

## Actor input object example

```json
{
  "from": "Paris Gare de Lyon",
  "to": "Lyon Part-Dieu",
  "departureTime": "08:00",
  "directOnly": false,
  "trainType": "all",
  "priceMode": "prices",
  "maxResults": 10,
  "maxLoadMoreClicks": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "groups": [
      "RESIDENTIAL"
    ],
    "countryCode": "FR"
  }
}
```

# Actor output Schema

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

One record per extracted SNCF Connect train connection.

## `output` (type: `string`):

Outcome, counts, resolved route, warnings, and charge-limit state.

# 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 = {
    "from": "Paris Gare de Lyon",
    "to": "Lyon Part-Dieu",
    "departureTime": "08:00",
    "maxResults": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "groups": [
            "RESIDENTIAL"
        ],
        "countryCode": "FR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/sncf-train-ticket-connection-scraper").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 = {
    "from": "Paris Gare de Lyon",
    "to": "Lyon Part-Dieu",
    "departureTime": "08:00",
    "maxResults": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "groups": ["RESIDENTIAL"],
        "countryCode": "FR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/sncf-train-ticket-connection-scraper").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 '{
  "from": "Paris Gare de Lyon",
  "to": "Lyon Part-Dieu",
  "departureTime": "08:00",
  "maxResults": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "groups": [
      "RESIDENTIAL"
    ],
    "countryCode": "FR"
  }
}' |
apify call muhammadafzal/sncf-train-ticket-connection-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/sncf-train-ticket-connection-scraper"
        }
    }
}
```

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/Tpa4vhVAed2v4DFxz/builds/DYwqM2HPVdzMUkVYO/openapi.json
