# Hugging Face Scraper - Models, Datasets, Spaces (`s-r/huggingface-scraper`) Actor

List and rank Hugging Face models, datasets and spaces by downloads, likes or trending score. Filter by task, author or search term. Returns licence, languages, base model, file list, gated status and dates from the official Hub API.

- **URL**: https://apify.com/s-r/huggingface-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 run start fees

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

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

## Hugging Face Scraper

List and rank **models, datasets and spaces** on the Hugging Face Hub by
downloads, likes or trending score. Filter by task, author or search term, or
look up specific repos by name.

Reads the **official Hub API**. No token needed for public repos.

### What you can actually ask it

**"What are the most downloaded embedding models right now?"** Sort by
downloads with a task filter and you get a ranked table:
`sentence-transformers/all-MiniLM-L6-v2` at 250 million downloads in 30 days,
then `cross-encoder/ms-marco-MiniLM-L6-v2` at 85 million, then
`BAAI/bge-small-en-v1.5` at 66 million.

**"Which models can we legally ship?"** Turn on full detail and filter on
`license`. Apache-2.0 and MIT are shippable; a good number of popular models
are not, and the licence is the field people discover too late.

**"What is everyone fine-tuning from?"** `base_model` names the parent, so you
can see which foundation models the ecosystem actually builds on.

**"What changed this month?"** Sort by `createdAt` or `lastModified` and get new
and freshly updated repos.

### Fields

- **Identity**: `id`, `repo_type`, `author`, `url`
- **Popularity**: `downloads_30d`, `likes`, `trending_score`
- **Classification**: `pipeline_tag` (the task), `library_name`, `tags`
- **Provenance**: `base_model`, `datasets_used`, `arxiv_ids`
- **Legal**: `license`
- **Reach**: `languages`
- **Access**: `gated`, `private`, `disabled`
- **Dates**: `created_at`, `last_modified`
- **Contents**: `file_count`, `files` (first 50)
- **Spaces only**: `sdk` (gradio, streamlit, docker)

### Three things about this data that catch people out

**`downloads_30d` is a 30-day figure, not a lifetime total.** The Hub reports
downloads over a rolling month. Reading it as all-time understates every new
model and overstates nothing; it simply is not the number most people assume it
is. The field is named for what it holds.

**Licence and file list only exist on the detail call.** A listing gives you
downloads, likes, tags and task. It does *not* carry `cardData`, which is where
the licence lives, nor `siblings`, which is the file list. Turn on **Fetch full
detail** and the Actor makes one extra call per repo to fill those in. When you
leave it off and licences come back partly empty, the run summary says so
instead of letting you conclude those models have no licence.

Looking up specific `repo_ids` always fetches detail, so that path is complete.

**`gated` is not `private`.** A gated repo is public and listed, but its files
need you to accept terms first. Llama models are the well-known case. You can
read all the metadata; you cannot download the weights without agreeing.

### A missing repo and a private one look identical

The Hub answers **HTTP 401 "Invalid username or password"** for a repo that does
not exist, exactly as it does for one that is private. That is deliberate: it
stops the API leaking whether a private repo exists.

So this Actor does not pretend to know which it hit. The error names both
possibilities. Anything else would be a guess dressed as a fact.

### The rate limit is published, so it is respected

Every Hub response carries its own limit:

```
ratelimit-policy: "fixed window";"api";q=500;w=300
ratelimit: "api";r=499;t=272
```

500 requests per 300 seconds, with the remaining count and seconds-to-reset on
every call. This Actor **reads both from the response** rather than assuming a
figure, and pauses until the window resets when fewer than five requests remain,
instead of running into a 429. The remaining allowance is reported in the run
summary.

One listing request returns 100 repos, so the window is generous: roughly 50,000
repos per five minutes without detail. With **Fetch full detail** on, every repo
costs an extra request, so a 500-repo run with detail uses about 505 of the 500
in the window and will pause once. That is expected, not a fault.

### Input reference

| Field | Type | Default |
|---|---|---|
| `repo_type` | models, datasets, spaces | `models` |
| `search` | free text over repo names | — |
| `task` | task tag, e.g. `text-generation` | — |
| `author` | user or organisation | — |
| `repo_ids` | list of exact repo ids | — |
| `sort` | downloads, likes, lastModified, createdAt, trendingScore | `downloads` |
| `direction` | desc, asc | `desc` |
| `detail` | fetch licence, languages, files | `false` |
| `token` | only for private or gated repos | — |
| `limit` | 1-3000 | 100 |
| `retries` | 1-6 | 3 |

### Typical uses

- **Model selection.** Rank by downloads within a task, then filter by licence
  and language to get a shortlist you can actually use.
- **Licence audit.** Feed your deployed model ids into `repo_ids` and read the
  licences back.
- **Ecosystem tracking.** Sort by `createdAt` weekly on a task and watch what is
  new. `base_model` shows the lineage.
- **Dataset discovery.** Switch `repo_type` to `datasets` and the same sorting
  and filtering applies.
- **Competitive research.** Filter by `author` to see an organisation's whole
  published output, with adoption numbers attached.

### Notes

Public repos need no token. Supply one only if you need private or gated repos,
and it will be sent as a bearer token; the rate limit is the same either way.

Tags on the Hub are freeform and inconsistent. `languages` prefers the model
card's own `language` field and falls back to `language:`-prefixed tags, because
most repos declare a bare `en` tag that carries no reliable meaning on its own.

# Actor input Schema

## `repo_type` (type: `string`):

Models, datasets or spaces. The same filters and sorts apply to all three.

## `search` (type: `string`):

Free-text search over repo names, for example llama or whisper.

## `task` (type: `string`):

Filter models by task tag, for example text-generation, text-classification or automatic-speech-recognition.

## `author` (type: `string`):

Only repos owned by this user or organisation, for example openai or meta-llama.

## `repo_ids` (type: `array`):

Look up named repos directly instead of listing, for example openai/whisper-large-v3. This always fetches full detail, so licence and file list are populated.

## `sort` (type: `string`):

Which repos come first.

## `direction` (type: `string`):

Descending puts the most downloaded or newest first.

## `detail` (type: `boolean`):

Make one extra call per repo to fill in licence, languages and the file list. Listings do not carry those. Slower and uses more of the rate-limit window.

## `token` (type: `string`):

Only needed for private or gated repos. Public listing works without one and the rate limit is the same.

## `limit` (type: `integer`):

How many repos to return.

## `retries` (type: `integer`):

Retries with backoff before a request is reported as an error.

## Actor input object example

```json
{
  "repo_type": "models",
  "search": "llama",
  "task": "text-generation",
  "sort": "downloads",
  "direction": "desc",
  "detail": false,
  "limit": 100,
  "retries": 3
}
```

# Actor output Schema

## `repos` (type: `string`):

One row per model, dataset or space.

## `summary` (type: `string`):

Counts, licence coverage and the remaining Hub rate-limit window.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# 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 = {
    "limit": 100,
    "retries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/huggingface-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 = {
    "limit": 100,
    "retries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/huggingface-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 '{
  "limit": 100,
  "retries": 3
}' |
apify call s-r/huggingface-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/huggingface-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/Zi8gFLbc19Cv3YncZ/builds/Sxi0VOhLVDJa3mIZg/openapi.json
