# Dev.to Scraper · Articles, Tags, Authors & Reactions (`reapx/devto-scraper`) Actor

Extract Dev.to articles, tags, authors, organizations, reactions, and top posts without authentication. Returns structured article metrics and metadata.

- **URL**: https://apify.com/reapx/devto-scraper.md
- **Developed by:** [Tarek Etman](https://apify.com/reapx) (community)
- **Categories:** Developer tools, Business, Other
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.85 / 1,000 dev.to article record scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

![reapX — public sources in, addressable records out](https://reapx.dev/reapx.gif)

## Dev.to Scraper · Articles, Tags, Authors & Reactions

Dev.to Scraper is an automated, high-performance web scraper and data extraction tool for Dev.to (the Forem developer network). Extract Dev.to articles, tutorials, technical blogs, author profiles, organization publications, reactions, comments count, and reading metrics without requiring API keys or authentication.

> Maintained by **reapX**. Every row cites the Apify run that produced it — nothing is inferred, modelled or filled in, and a field absent from the source is absent from the row. The extracted archive for this source is browsable at [reapx.dev/data/devto-scraper/](https://reapx.dev/data/devto-scraper/) and mirrored as an open dataset on [Hugging Face](https://huggingface.co/datasets/reapxdev/devto-scraper) and [Kaggle](https://www.kaggle.com/datasets/reapxdev/devto-scraper). Questions: reapxdev@proton.me

***

### ⬇️ Input

The actor accepts structured JSON input specifying filtering options such as primary tag, multi-tag lists, author usernames, organization handles, publication state (`rising`, `fresh`, `all`), top time windows in days, and maximum result limits.

#### Input Parameters

| Parameter | Type | Default | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `tag` | String | `"javascript"` | Primary Dev.to tag to filter articles. | `"python"` |
| `tags` | String | `null` | Comma-separated list of tags to filter articles. | `"react, typescript"` |
| `username` | String | `null` | Author username to filter articles. | `"ben"` |
| `organization` | String | `null` | Organization slug to filter corporate/org blogs. | `"gde"` |
| `top` | Integer | `null` | Time window in days for top articles (e.g. 7, 30, 365). | `7` |
| `state` | String | `null` | Publication state filter (`all`, `rising`, `fresh`). | `"rising"` |
| `maxArticles` | Integer | `100` | Maximum number of article records to extract. | `100` |

#### Example Input JSON

```json
{
  "tag": "python",
  "top": 30,
  "state": "rising",
  "maxArticles": 100
}
```

```json
{
  "username": "ben",
  "maxArticles": 50
}
```

```json
{
  "organization": "gde",
  "maxArticles": 50
}
```

***

### ⬆️ Output

The scraper outputs structured article records directly to the default Apify dataset. Every output record contains camelCase attributes, ASCII-normalised article `slug` values, author handles, organization details, reaction counts, and canonical URLs.

#### Output Fields Schema

| Field Name | Type | Description | Example |
| :--- | :--- | :--- | :--- |
| `articleId` | Integer | Unique Dev.to article numeric identifier. | `4265440` |
| `slug` | String | ASCII-normalised addressable article slug. | `"amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b"` |
| `title` | String | Full title of the published article. | `"Amazon Bedrock Agents Orchestrating Google ADK over A2A"` |
| `description` | String | Short summary or description snippet of the article. | `"This article explains how to build a cross-cloud currency agent..."` |
| `url` | String | Direct Dev.to post web URL. | `"https://dev.to/gde/amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b"` |
| `path` | String | Relative URL path on Dev.to. | `"/gde/amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b"` |
| `publishedAt` | String | ISO 8601 publication timestamp. | `"2026-07-29T19:14:47Z"` |
| `readablePublishDate` | String | Human-readable publish date snippet. | `"Jul 29"` |
| `commentsCount` | Integer | Total count of comments on the post. | `5` |
| `publicReactionsCount` | Integer | Total count of public reactions (likes, hearts, unicorns). | `42` |
| `positiveReactionsCount` | Integer | Count of positive reactions. | `42` |
| `readingTimeMinutes` | Integer | Estimated reading time in minutes. | `9` |
| `language` | String | Primary article language code. | `"en"` |
| `tags` | String | Comma-separated list of tags. | `"agents, googleadk, a2aprotocol, aws"` |
| `tagList` | Array | List of tag strings. | `["agents", "googleadk", "aws"]` |
| `coverImage` | String | Header cover image URL. | `"https://media2.dev.to/.../cover.png"` |
| `socialImage` | String | Social preview image URL. | `"https://media2.dev.to/.../social.png"` |
| `canonicalUrl` | String | Original canonical URL. | `"https://dev.to/gde/..."` |
| `authorUsername` | String | Username of the author. | `"xbill"` |
| `authorName` | String | Display name of the author. | `"xbill"` |
| `authorUserId` | Integer | Dev.to user ID of the author. | `3490099` |
| `authorProfileImage` | String | Author profile avatar image URL. | `"https://media2.dev.to/.../profile.jpg"` |
| `authorGithubUsername` | String | Author's GitHub username handle. | `"xbill9"` |
| `organizationSlug` | String | Slug of publishing organization. | `"gde"` |
| `organizationName` | String | Name of publishing organization. | `"Google Developer Experts"` |

#### Sample Output Record JSON

```json
{
  "articleId": 4265440,
  "slug": "amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b",
  "title": "Amazon Bedrock Agents Orchestrating Google ADK over A2A",
  "description": "This article explains how to build and test a cross-cloud currency agent. An Amazon Bedrock master...",
  "url": "https://dev.to/gde/amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b",
  "path": "/gde/amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b",
  "publishedAt": "2026-07-29T19:14:47Z",
  "publishedTimestamp": "2026-07-29T19:14:47Z",
  "readablePublishDate": "Jul 29",
  "commentsCount": 0,
  "publicReactionsCount": 9,
  "positiveReactionsCount": 9,
  "readingTimeMinutes": 9,
  "language": "en",
  "tags": "agents, googleadk, a2aprotocol, aws",
  "tagList": [
    "agents",
    "googleadk",
    "a2aprotocol",
    "aws"
  ],
  "coverImage": "https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fxbill9%2Fbedrock-adk-a2a-currency%2Fmain%2Fdevto-cover-bedrock-master.png",
  "socialImage": "https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fxbill9%2Fbedrock-adk-a2a-currency%2Fmain%2Fdevto-cover-bedrock-master.png",
  "canonicalUrl": "https://dev.to/gde/amazon-bedrock-agents-orchestrating-google-adk-over-a2a-5c2b",
  "createdAt": "2026-07-29T19:14:47Z",
  "editedAt": "2026-07-29T19:14:56Z",
  "authorUsername": "xbill",
  "authorName": "xbill",
  "authorUserId": 3490099,
  "authorProfileImage": "https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3490099%2Fc6a975d0-cd94-485d-82b1-14ed5b344fcf.jpg",
  "authorGithubUsername": "xbill9",
  "authorTwitterUsername": null,
  "authorWebsiteUrl": "https://g.dev/xbill",
  "organizationSlug": "gde",
  "organizationName": "Google Developer Experts",
  "organizationUsername": "gde",
  "organizationProfileImage": "https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F11939%2Fe3080d5b-ecde-42a8-b089-bafecc31fa97.png"
}
```

***

### How it works

Dev.to Scraper queries the official public REST endpoints of Dev.to (`https://dev.to/api/articles`) using lightweight HTTP requests with automatic pagination and exponential backoff retry handling.

1. **Parameter Construction**: The actor formats requested tag, author, organization, top period, and state filters.
2. **Paginated Retrieval**: Requests articles in batches of 50 to maximize speed and throughput.
3. **Data Transformation & Normalization**:
   - Re-keys `id` to `articleId` so numeric IDs do not interfere with entity page addressing.
   - ASCII-normalises and sanitizes article `slug` strings to ensure valid, unique entity keys across datasets.
   - Flattens nested author (`user`) and organization (`organization`) objects into accessible camelCase fields.
4. **Pay-Per-Event Billing**: Charges $0.001 per scraped article record (`article-scraped`) before pushing items to the dataset, with full budget check protection.

***

### ❓ FAQ

#### Does Dev.to Scraper require an API key?

No. Dev.to public REST endpoints do not require authentication or API keys.

#### How are article slugs normalized?

Article slugs are converted from unicode to clean ASCII strings, removing invalid non-alphanumeric characters and truncating to a maximum length of 80 characters. This ensures total compatibility with entity page generators and page indexing engines.

#### How does Pay-Per-Event pricing work?

You only pay for the actual article records returned and stored in your dataset ($0.001 per record). Tiered discounts automatically reduce unit pricing for Bronze, Silver, Gold, Platinum, and Diamond accounts.

#### Can I filter by specific organizations or companies?

Yes, pass the organization handle (such as `gde`, `aws`, `forem`, or `supabase`) in the `organization` input field.

#### Can I fetch top posts over a specific period?

Yes, pass `top` set to `7` (last 7 days), `30` (last 30 days), or `365` (last year).

***

### 💬 Your feedback

We continuously improve our scrapers based on user feedback. If you discover a bug, request a feature, or need custom data pipelines, please reach out to **reapxdev@proton.me** or visit [reapx.dev](https://reapx.dev).

***

### Disclaimer

Unofficial - not affiliated with Dev.to or Forem. Collects public data only. reapx. Contact reapxdev@proton.me.

### 🧪 Example input

A real, runnable configuration — this is an actual input this Actor has run with.

```json
{
  "tag": "javascript",
  "maxArticles": 50
}
```

### 📄 Sample output

One real row from a real run of this Actor, unedited.

```json
{
  "type_of": "article",
  "title": "TypeScript 7 Went Native: What Actually Changes And What Doesn't",
  "description": "Everyone's heard by now that TypeScript \"went native.\" And I keep seeing the same wrong conclusion...",
  "readable_publish_date": "Aug 3",
  "slug": "typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3",
  "path": "/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3",
  "url": "https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3",
  "comments_count": 33,
  "public_reactions_count": 68,
  "collection_id": null,
  "published_timestamp": "2026-08-03T13:11:18Z",
  "language": "en",
  "subforem_id": 1,
  "positive_reactions_count": 68,
  "cover_image": "https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fimages.weserv.nl%2F%3Furl%3Dwww.nazarboyko.com%2Fassets%2Fimgs%2Farticles%2Ftypescript-7-native-compiler-what-changes%2Fcover.webp%26w%3D1600%26h%3D672%26fit%3Dcover%26a%3Dtop",
  "social_image": "https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fimages.weserv.nl%2F%3Furl%3Dwww.nazarboyko.com%2Fassets%2Fimgs%2Farticles%2Ftypescript-7-native-compiler-what-changes%2Fcover.webp%26w%3D1600%26h%3D672%26fit%3Dcover%26a%3Dtop",
  "canonical_url": "https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3",
  "created_at": "2026-08-03T03:21:53Z",
  "edited_at": null,
  "crossposted_at": null,
  "published_at": "2026-08-03T13:11:18Z",
  "last_comment_at": "2026-08-03T18:07:51Z",
  "reading_time_minutes": 8,
  "tag_list": [
    "discuss",
    "javascript",
    "typescript",
    "performance"
  ],
  "tags": "discuss, javascript, typescript, performance",
  "flare_tag": {
    "name": "discuss",
    "bg_color_hex": "#71EA8B",
    "text_color_hex": "#FFFFFF"
  },
  "articleId": 4296692,
  "authorUsername": "nazar-boyko",
  "authorName": "Nazar Boyko",
  "authorUserId": 1875383,
  "authorProfileImage": "https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1875383%2F1b3f5dc9-df1c-4551-9f6e-e3b6234b3d6c.gif",
  "authorGithubUsername": null,
  "authorTwitterUsername": null,
  "authorWebsiteUrl": "http://nazarboyko.com/",
  "organizationSlug": null,
  "organizationName": null,
  "organizationUsername": null,
  "organizationProfileImage": null,
  "publishedAt": "2026-08-03T13:11:18Z",
  "publishedTimestamp": "2026-08-03T13:11:18Z",
  "readablePublishDate": "Aug 3",
  "commentsCount": 33,
  "publicReactionsCount": 68,
  "positiveReactionsCount": 68,
  "readingTimeMinutes": 8,
  "coverImage": "https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fimages.weserv.nl%2F%3Furl%3Dwww.nazarboyko.com%2Fassets%2Fimgs%2Farticles%2Ftypescript-7-native-compiler-what-changes%2Fcover.webp%26w%3D1600%26h%3D672%26fit%3Dcover%26a%3Dtop",
  "socialImage": "https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3
```

### ⚠️ Run outcomes and error handling

This Actor reports what happened in the run's **status message**, and it always keeps whatever it collected. These are the outcomes you can get and what each one means.

| Outcome | What it means |
|---|---|
| **Success** | Rows were returned and you were charged `article-scraped` at $0.001 per row. |
| **No matches** | The source returned nothing for your filters. **Nothing is charged.** Widen the date window or drop a filter. |

#### What is guaranteed either way

- **Every row is pushed as it is built**, not buffered to the end of the run. Anything that buffers output loses everything to a timeout, a block or a migration; this does not.
- **A field absent from the source is absent from the row.** Nothing is inferred, modelled or filled in to make a row look complete.

# Actor input Schema

## `tag` (type: `string`):

<b>Filter articles by a primary Dev.to tag</b> (e.g., <code>python</code>, <code>javascript</code>, or <code>webdev</code>). <br><br>Leave empty to scrape posts across all tags without tag filtering. <i>Consequence:</i> Narrowing by tag speeds up execution, narrows the search scope, and returns highly relevant community articles for the specific topic.

## `tags` (type: `string`):

<b>Filter articles by a comma-separated list of tags</b> (e.g., <code>react, typescript, nextjs</code>). <br><br>Leave empty to skip multi-tag filtering constraint. <i>Consequence:</i> Matches posts tagged with any of the requested topics, giving broader multi-topic coverage per run.

## `username` (type: `string`):

<b>Filter articles written by a specific Dev.to author or creator</b> (e.g., <code>ben</code> or <code>sentry</code>). <br><br>Leave empty to include posts from all authors across the platform. <i>Consequence:</i> Restricts results strictly to the specified author profile and their published technical posts.

## `organization` (type: `string`):

<b>Filter articles published under an official organization slug</b> (e.g., <code>gde</code> or <code>aws</code>). <br><br>Leave empty to include independent author and organization posts alike. <i>Consequence:</i> Filters for official corporate or tech organization blogs and team engineering updates.

## `top` (type: `integer`):

<b>Filter top-performing articles by time window in days</b> (e.g., <code>7</code> for weekly top posts, <code>30</code> for monthly, <code>365</code> for yearly). <br><br>Leave empty for standard chronological feed ordering. <i>Consequence:</i> Retrieves the highest reaction and engagement developer content over the selected window.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

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

<b>Filter articles by publication state or feed category</b> (e.g., <code>all</code>, <code>rising</code>, or <code>fresh</code>). <br><br>Leave empty for standard default state filtering. <i>Consequence:</i> Targets newly posted or fast-rising trending articles before they reach peak popularity.

## `maxArticles` (type: `integer`):

<b>Maximum number of articles to extract and save</b> to the default dataset storage. <br><br>Default limit is set to 100 articles. <i>Consequence:</i> The higher the number, the longer the run takes and the more event records are billed. Set a lower limit for quick tests and higher for full scraping runs.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

## Actor input object example

```json
{
  "tag": "javascript",
  "tags": "react, typescript",
  "username": "ben",
  "organization": "gde",
  "top": 7,
  "state": "rising",
  "maxArticles": 100
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing scraped Dev.to article records

# 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 = {
    "tag": "javascript",
    "maxArticles": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("reapx/devto-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 = {
    "tag": "javascript",
    "maxArticles": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("reapx/devto-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 '{
  "tag": "javascript",
  "maxArticles": 100
}' |
apify call reapx/devto-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reapx/devto-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/b0AIUcIEkrg9CKczE/builds/86jwmn3eTyATkQ3aN/openapi.json
