DEV APIdev.to ↗
Retrieve DEV Community latest articles with title, author, tags, and reaction counts. Filter by tag, paginate results, and track engagement metrics.
What is the DEV API?
The DEV Community API exposes one endpoint — list_latest_articles — that returns a paginated feed of the newest articles published on dev.to, each record carrying 10+ fields including title, author identity (name, username, user_id), tag list, public reaction count, positive reaction count, comment count, reading time, and a direct URL to the post. A single call can return up to 100 articles and supports optional filtering by tag slug.
curl -X GET 'https://api.parse.bot/scraper/bd458506-27a8-4879-b7e2-5d65e2ea7023/list_latest_articles?tag=javascript&per_page=5' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace dev-to-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: DEV Community latest-articles feed — bounded, re-runnable."""
from parse_apis.dev_to_api import DevTo, InputFormatInvalid
client = DevTo()
# Browse the latest articles across all tags, capped to 5 items.
for article in client.articles.list(per_page=5, limit=5):
print(article.title, f"({article.reading_time_minutes}m read)")
print(f" by {article.author.name} (@{article.author.username})")
print(f" tags: {', '.join(article.tags)} reactions: {article.reactions_count}")
# Narrow to a single tag and grab the first result for drill-down.
try:
top_python = client.articles.list(tag="python", limit=1).first()
except InputFormatInvalid as e:
print(f"Bad request: {e.message}")
top_python = None
if top_python is not None:
print(f"\nTop Python article: {top_python.title}")
print(f" {top_python.url}")
print(f" published: {top_python.published_at} comments: {top_python.comments_count}")
print("\nexercised: articles.list (all + tag-filtered)")
Returns one page of the DEV Community 'Latest' feed, newest published first. Each record is one article with its title, author (name, username, id), tag list, public reaction count, positive reaction count and comment count. One upstream request per call. Pagination is page-based: page selects the page (defaults to 1) and per_page sets the page size (defaults to 30, clamped to 100); has_more is true when the page came back full, so callers continue by incrementing page until has_more is false. An optional tag restricts the feed to articles carrying that tag; an unknown tag yields an empty articles array, which is a valid result.
| Param | Type | Description |
|---|---|---|
| tag | string | Tag slug as shown on the site without the leading #, e.g. one shape is javascript. Omitted = all articles. |
| page | integer | 1-based page number of the feed. |
| per_page | integer | Articles per page; values above 100 are clamped to 100. |
{
"type": "object",
"fields": {
"tag": "tag filter applied, or null",
"page": "integer page number served",
"count": "integer number of articles in this page",
"articles": "array of articles: id, title, description, url, published_at (ISO 8601), reading_time_minutes, author {name, username, user_id, profile_image}, organization (name or null), tags (array of tag slugs), reactions_count (public reactions), positive_reactions_count, comments_count",
"has_more": "boolean, true when the page was full and a further page may exist",
"per_page": "integer page size applied after clamping"
},
"sample": {
"data": {
"tag": null,
"page": 1,
"count": 5,
"articles": [
{
"id": 3254485,
"url": "https://dev.to/beck_moulton/stop-guessing-use-causal-inference-to-analyze-your-health-habits-with-python-and-dowhy-28ia",
"tags": [
"ai",
"discuss",
"opensource",
"react"
],
"title": "Stop Guessing! Use Causal Inference to Analyze Your Health Habits with Python and DoWhy",
"author": {
"name": "Beck_Moulton",
"user_id": 913145,
"username": "beck_moulton",
"profile_image": "https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/..."
},
"description": "We've all been there: staring at a Fitbit or Apple Health dashboard...",
"organization": null,
"published_at": "2026-09-03T00:46:00Z",
"comments_count": 0,
"reactions_count": 0,
"reading_time_minutes": 4,
"positive_reactions_count": 0
}
],
"has_more": true,
"per_page": 5
},
"status": "success"
}
}About the DEV API
What the API Returns
The list_latest_articles endpoint returns one page of the DEV Community 'Latest' feed ordered newest-first. Each article object includes id, title, description, url, published_at (ISO 8601 timestamp), reading_time_minutes, and engagement counters: public_reactions_count, positive_reactions_count, and comments_count. The author sub-object contains name, username, and user_id, giving you enough to identify contributors and link back to their profiles.
Filtering and Pagination
Pass a tag parameter (the slug without # — for example javascript, python, or beginners) to narrow the feed to a single topic. Combine this with the page integer parameter to walk forward through results. The per_page parameter controls page size and is clamped to a maximum of 100. The response includes a has_more boolean that is true when the current page was full and at least one additional page likely exists, removing the need to guess when to stop paginating.
Response Shape Details
Every response wraps the article array alongside metadata fields: tag (the filter applied, or null), page, per_page, and count (actual articles returned on this page). This lets you handle partial last pages cleanly — count may be less than per_page on the final page even when has_more is false. Reading time is given in whole minutes, making it straightforward to bucket content by length.
The DEV API is a managed, monitored endpoint for dev.to — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when dev.to changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official dev.to API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a tag-specific newsletter digest by filtering
list_latest_articleswith a tag slug and sorting bypublic_reactions_count. - Track trending topics on DEV by monitoring which tags produce the most articles per time window using
published_attimestamps. - Aggregate author activity by collecting
author.usernameacross pages to identify prolific contributors in a given category. - Populate a developer blog aggregator with fresh article titles, descriptions, and URLs refreshed on a schedule.
- Measure community engagement over time by storing
comments_countandpositive_reactions_countper article across repeated fetches. - Filter beginner-friendly content by combining the
beginnerstag withreading_time_minutesto surface short, accessible posts. - Build a reading queue tool that pages through the full feed and deduplicates articles by
idacross multiplepagevalues.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does DEV Community have an official developer API?+
What does the `has_more` field tell me, and can I rely on it as a definitive pagination signal?+
has_more is true when the page returned was full (equal to per_page), indicating a subsequent page likely exists. It is a heuristic rather than a guaranteed count: the very last page of the feed may return a full page by coincidence, causing one extra empty fetch. Always check that the returned count is greater than zero to confirm real results.Does the API return full article body content?+
description field (a short excerpt) but not the full body markdown or HTML. The url field points to the canonical DEV post where the full text is readable. You can fork this API on Parse and revise it to add a detail endpoint that fetches the full article body by id.Can I retrieve articles for a specific author or user profile?+
name, username, user_id) is present in each article object, but there is no parameter to filter by author. You can fork it on Parse and revise to add a per-author endpoint.How fresh is the data returned by `list_latest_articles`?+
public_reactions_count and comments_count are point-in-time snapshots at the moment of the request and will not update automatically — you need to re-query to see updated counts.