# Opendatasoft Portals Scraper (`bigibyte/opendatasoft-portals-scraper`) Actor

Opendatasoft Portal Scraper pulls public rows from any Explore Data portal like Paris, Toulouse, or Infogreffe. Pick a dataset, add an optional ODSQL filter, and export clean JSON, CSV, or Excel. Records and catalog modes, with paging, dedupe, retries, and scheduling to keep your data fresh.

- **URL**: https://apify.com/bigibyte/opendatasoft-portals-scraper.md
- **Developed by:** [BigiByte](https://apify.com/bigibyte) (community)
- **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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Opendatasoft Portal Scraper: Any ODS Portal

<p align="center">
  <img src="https://imgur.com/FhsAvOH.png" alt="USA Automotive Leads Hub" style="max-width:100%; border-radius:14px; width:680px;" />
</p>

This scraper exports public rows and catalog details from municipal and business open data portals like Paris, Toulouse, and Infogreffe. Just point it at a portal, pick a dataset, and optionally add a filter clause. You'll get a clean dataset ready to download as JSON, CSV, or Excel.

***

### What This Actor Extracts

- **Records Mode**: Saves one row per dataset record while keeping all original field names intact. On transit feeds, for example, this includes station codes, names, dock and bike counts, status flags, coordinates, and commune details. Longitude and latitude are also neatly flattened out for easy mapping.
- **Catalog Mode**: Saves one row per dataset available on the portal, giving you the slug, title, summary, license, keywords, and a complete list of field names.

Every exported row includes a timestamp (`scrapedAt`) and a source reference (`sourceUrl`). If a row can't be produced, it's logged as a clean error row with a short message, so the rest of the run continues smoothly without crashing.

***

### Use Cases

- Schedule regular exports of real-time availability feeds or municipal datasets.
- Explore every dataset on a portal, along with its license and field names, before deciding what to download.
- Apply custom filter clauses to keep only the records that match your criteria.
- Quickly grab a few hundred public rows for a data science notebook without any setup overhead.
- Rerun the same inputs over time to compare changes and track updates.

***

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `records` | Choose `records` to export a specific dataset, or `catalog` to list datasets available on the portal. |
| `portalUrl` | string | `https://opendata.paris.fr` | Base web address of the target public data portal. |
| `datasetId` | string | `velib-disponibilite-en-temps-reel` | Dataset slug to target when running in records mode. |
| `where` | string | *empty* | Optional filter clause used exclusively in records mode. |
| `maxItems` | integer | `100` | Row cap for the run (hard maximum of 1,000 items). |
| `timeoutSecs` | integer | `300` | Stop the run after this many seconds. |
| `requestTimeoutSecs` | integer | `30` | How long to wait before timing out. |
| `proxyConfiguration` | object | `{"useApifyProxy": false}` | Optional proxy settings. Leave it turned off unless you have a specific routing need. |

#### Example Input

```json
{
  "mode": "records",
  "portalUrl": "https://opendata.paris.fr",
  "datasetId": "velib-disponibilite-en-temps-reel",
  "where": "",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": { "useApifyProxy": false }
}

```

***

### Output Example

A sample record export looks like this:

```json
{
  "stationcode": "40001",
  "name": "Hôpital Mondor",
  "is_installed": "OUI",
  "capacity": 28,
  "numdocksavailable": 23,
  "numbikesavailable": 5,
  "mechanical": 0,
  "ebike": 5,
  "is_renting": "OUI",
  "is_returning": "OUI",
  "duedate": "2026-10-11T20:32:26+00:00",
  "coordonnees_geo": { "lon": 2.4537451531298, "lat": 48.798922410229 },
  "longitude": 2.4537451531298,
  "latitude": 48.798922410229,
  "nom_arrondissement_communes": "Créteil",
  "code_insee_commune": "94028",
  "scrapedAt": "2026-10-12T00:00:00+00:00",
  "sourceUrl": "https://opendata.paris.fr/explore/dataset/velib-disponibilite-en-temps-reel/"
}

```

***

### Related Tools

If you plan to map or join these rows, a geocoding pass or a quick CSV cleanup are the usual next steps. BigiByte also builds scrapers for other open-data portals when you need them as a separate job.

Need another city's open data, a scheduled monitor, or a custom pipeline? BigiByte builds custom scrapers and data pipelines: https://bigibyte.com

***

### Trademark Notice & Disclaimer

Portals and related names, logos, and trademarks belong to their respective owners. Their mention here is solely for identification purposes and does not imply affiliation, sponsorship, endorsement, or partnership.

This actor is an independent tool designed to collect publicly available information. Users are fully responsible for complying with the source's terms of use, any usage restrictions, and attribution or licensing requirements.

#### Is web scraping legal?

This Actor only collects publicly available data from Opendatasoft Portals without bypassing any access controls. Scraping public data is generally legal, but how you use it matters:

- **Personal data:** If the results include personal data (for example names, emails, or profile details), laws such as the GDPR in the EU and the CCPA in California may apply. Only collect and store personal data when you have a legitimate reason.
- **Copyright:** Some content (articles, images, descriptions) may be protected by copyright. Do not republish full copyrighted content without permission.
- **Terms of use:** Respect the source's terms, any usage restrictions, and any attribution or non-commercial-use requirements.
- **Legal advice:** This is general information, not legal advice. If you're unsure, consult a lawyer.

To learn more, read Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

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

Choose records to export rows from one dataset, or catalog to list datasets on the portal.

## `portalUrl` (type: `string`):

Base URL of a public Opendatasoft portal, such as https://opendata.paris.fr.

## `datasetId` (type: `string`):

Dataset slug used in records mode. Ignored when mode is catalog. The Paris Velib feed is a working default.

## `where` (type: `string`):

Optional ODSQL filter for records mode, for example numbikesavailable > 0. Leave empty to take every row the page window allows.

## `maxItems` (type: `integer`):

Maximum rows to save in one run, including an error row if a request fails. Hard cap is 1000.

## `timeoutSecs` (type: `integer`):

Stop the run after this many seconds, even if maxItems is not reached.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single HTTP response before retrying.

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

Optional proxy for requests. Leave Apify Proxy off. Do not use a proxy to get around a portal rate limit.

## Actor input object example

```json
{
  "mode": "records",
  "portalUrl": "https://opendata.paris.fr",
  "datasetId": "velib-disponibilite-en-temps-reel",
  "where": "numbikesavailable > 0",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `datasetUrl` (type: `string`):

No description

## `overviewUrl` (type: `string`):

No description

## `catalogUrl` (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": "records",
    "portalUrl": "https://opendata.paris.fr",
    "datasetId": "velib-disponibilite-en-temps-reel",
    "where": "",
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("bigibyte/opendatasoft-portals-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 = {
    "mode": "records",
    "portalUrl": "https://opendata.paris.fr",
    "datasetId": "velib-disponibilite-en-temps-reel",
    "where": "",
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("bigibyte/opendatasoft-portals-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 '{
  "mode": "records",
  "portalUrl": "https://opendata.paris.fr",
  "datasetId": "velib-disponibilite-en-temps-reel",
  "where": "",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call bigibyte/opendatasoft-portals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bigibyte/opendatasoft-portals-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/fs2AbxONjvXPZYJxK/builds/cEhmpvcSldVP6QVhB/openapi.json
