# Article & Reel Maker (`calin_a/article-reel-maker`) Actor

Finds the news on a subject, researches a story, writes an original article with SEO fields and social captions, optionally drafts it to WordPress and renders a vertical video reel.

- **URL**: https://apify.com/calin_a/article-reel-maker.md
- **Developed by:** [Calin A](https://apify.com/calin_a) (community)
- **Categories:** AI, News, Social media
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 article writtens

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

### What does Article & Reel Maker do?

**Article & Reel Maker** turns the news on your subject into ready-to-publish content. Describe your niche in plain words, such as "UK education news" or "Formula 1", and it will:

- 📰 **find today's stories** on that subject in Google News, ranked by relevance, freshness and where they happened;
- 🔎 **research** a story from several current sources, or from one link, or from your own press release or notes;
- ✍️ **write an original article** in English, with source markers, an SEO title, slug, meta description and keywords, three Facebook captions and a short-video caption;
- 🌐 **post it to WordPress** as a draft or published, with tags and your featured image (optional);
- 🎬 **render a vertical video reel** (1080×1920, about 12 seconds, with music) for Reels, Shorts or TikTok (optional).

Run it once, or put it on a schedule and it will keep writing the newest stories without ever repeating one.

### Who is it for?

- **Niche news sites and blogs** that want a steady flow of timely articles without writing each one from scratch.
- **Social media managers** who need captions and short videos for every story.
- **Agencies** running several sites: one saved task per site, each with its own memory.

### How to use it

Choose one of three modes.

#### 1. Find topics: see what is in the news

1. Set **What to do** to *Find topics*.
2. Enter **Your subject**, e.g. `UK education news`.
3. Start. Each result row is one story, with its rank, the publisher, how old it is and why it scored as it did.

Every row carries a ready-made entry (`writeArticlesEntry`) to paste into a Write articles run.

#### 2. Write articles: write the stories you choose

1. Set **What to do** to *Write articles*.
2. Fill **Articles to write** with one entry per article. Each entry is one of these:
   - a **topic**, researched from several current sources: `{"topic": "Teachers vote to strike over pay"}`;
   - a **link**, rewritten from that one page: `{"url": "https://example.com/news/story"}`;
   - **your own text**, used as it is with no search: `{"topic": "New library opens", "sources": [{"title": "Council press release", "text": "..."}]}`.
3. Optionally add `"imageUrl"` and `"imageAlt"` to an entry for its featured image and reel photo.

#### 3. Find and write: hands-off

Set **What to do** to *Find and write*, **Number of articles** to how many to write, and **Date range** to how far back to look: from the last 24 hours to the last 30 days. It finds the news, then writes the best stories that no earlier run has written. Add a [schedule](https://docs.apify.com/platform/schedules) to publish several times a day.

### Input

Only **Your subject** is needed to start. The other sections are optional:

| Section | What it sets |
|---|---|
| Advanced discovery | Your own Google News searches, language and country, what counts as domestic, relevance keywords, trusted outlets. Fill these to override what is worked out from your subject. |
| Research | How old a source may be (7 days by default; 0 for evergreen topics). |
| Writing | AI model, your site's name and description, British or American English, source markers, minimum length, your own hashtags. |
| WordPress | Site address, username, application password, draft or publish, category, SEO plugin field prefix. |
| Reel | On or off, style, the name, address and section label shown, and your logo. |
| Memory | The storage that remembers written stories (one per site). |

### Output

One dataset row per article. Download it as JSON, CSV or Excel, or read it through the API. A shortened example:

```json
{
  "request": "Teachers vote to strike over pay",
  "status": "written",
  "title": "Teachers Back Strike Action in Pay Dispute",
  "wordCount": 412,
  "contentHtml": "<p>Teachers have voted to ...</p>",
  "contentText": "Teachers have voted to ...",
  "seo": {
    "slug": "teachers-strike-pay-dispute",
    "searchEngineTitle": "Teachers Vote to Strike Over Pay",
    "metaDescription": "Teachers have backed strike action ...",
    "keywords": "teachers strike, pay dispute, unions",
    "imageAltText": "Teachers on a picket line"
  },
  "facebookCaptions": ["...", "...", "..."],
  "reelCaption": "... #teachers #strike",
  "sources": [{"title": "...", "url": "https://...", "domain": "..."}],
  "wordpress": {"id": 128, "status": "draft", "editUrl": "https://example.com/wp-admin/post.php?post=128&action=edit"},
  "reel": {"url": "https://api.apify.com/v2/key-value-stores/.../records/reel-...", "look": "broadcast:photo", "sizeMb": 1.4},
  "model": "google/gemini-2.5-flash",
  "usage": {"promptTokens": 4950, "completionTokens": 760}
}
```

An article that could not be written still gets a row, with `status: "failed"` and an `error` saying why: for example, no usable sources were found.

### Posting to WordPress

1. In WordPress, go to **Users → Profile → Application Passwords**, enter a name such as "Apify" and click **Add New Application Password**.
2. Copy the password into **WordPress application password**, with your site address and username.
3. Leave **Post as** on *Draft* until you are happy with the results.

The application password is stored encrypted, is not your login password, and can be revoked in WordPress at any time. The connection is checked before anything is written, so a wrong password costs nothing.

**SEO fields** are saved for an SEO plugin that accepts them through the REST API. Set the field prefix for yours: `hmt_` for Head Meta Tags, `rank_math_` for Rank Math. Check the page source of the first post to confirm they arrived.

**Firewalls:** if your site sits behind Cloudflare or a security plugin, it may need to allow requests from Apify.

### Reels

Tick **Make a reel** and each article also gets a short vertical video: the headline over your photo, a one-line summary, then your name, a call to action and your web address.

- **Styles:** *Rotate* walks through ten designed looks, one per reel, continuing across runs. You can also fix one style, or use the simpler presets.
- **Photo:** the article's `imageUrl`, or the default image for Find and write. Photos are never taken from the news sources, which are other publishers' property. Without a photo, a reel is still made in a plain style.
- **Logo:** upload one or give a link. Without one, your publication's name is shown instead.
- **Where they are kept:** in your memory storage, with a link on the article's row. They stay until you delete them. A run's own storage is deleted after your plan's retention period, so they are not kept there.
- **Memory:** runs with reels start with 4 GB of memory and take about a minute longer per article. Runs without reels use 1 GB.

### Never writing the same story twice

Both writing modes record what they wrote in your memory storage (*Memory storage name*) for 31 days. Find and write skips any story already written, including another outlet's version of the same story. If you run several sites, give each its own storage name.

### How much does it cost?

You pay only for what you get. Platform usage is included.

| Event | Price |
|---|---|
| Topic found (each ranked story from *Find topics*) | $0.001 |
| Article written | $0.04 |
| Reel rendered | $0.10 |

Failed articles and failed reels are free. A *Find topics* run of 50 stories costs $0.05; an article with its reel costs $0.14.

**Research and AI are billed separately** by the two Apify Actors this one uses, at their own prices:

- [RAG Web Browser](https://apify.com/apify/rag-web-browser) searches and reads the sources: usually 2–4.5 cents per article on the Apify free plan, less on paid plans. Articles written from your own text make no search.
- [OpenRouter](https://apify.com/apify/openrouter) runs the AI model by the tokens used: about half a cent per article with the default model on paid plans. On the Apify free plan, AI is charged at ten times that.

Working out search settings from your subject takes one small AI call, saved for 30 days. Every article row's `usage` field shows the tokens used. To cap what a run can cost, set a maximum charge per run in the run options: the Actor stops before an article or reel the limit would not cover, so you never lose one half-made.

### Good to know

- **Review before you publish.** The articles are written by AI from the sources it found. They are told to keep to the facts in those sources, but they can still contain mistakes. Posting as *Draft* lets you check each one first.
- **Articles are in English.** The news you search can be in any language Google News covers.
- **Images:** use only images you have the right to publish.
- **Apify free plan:** AI replies are capped at 2,048 tokens. That is enough for the default model; some reasoning models run out of room and are retried.
- Google News results vary from one search to the next, so the same subject may give slightly different stories a few minutes apart.

### FAQ

**Can I choose the stories myself?** Yes. Run *Find topics*, pick the rows you want, and paste their `writeArticlesEntry` values into a *Write articles* run.

**Can I use a different AI model?** Yes. Enter any OpenRouter model id under **AI model**, e.g. `anthropic/claude-haiku-4.5`.

**Can I write from my own material?** Yes. Give an entry `sources` with your text, and no search is made.

**Something went wrong.** Open the run's log: each step says what it did and why something was skipped. Failed articles also carry an `error` on their row.

# Actor input Schema

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

Find topics: rank today's news on your subject. Write articles: write up the topics or links you supply. Find and write: find the news, then write the top stories not already written by an earlier run.

## `subject` (type: `string`):

Describe your niche in plain words, e.g. "UK education news" or "Formula 1". The search terms, ranking keywords and home country are worked out from this. To control them yourself, fill in the advanced discovery settings instead.

## `articles` (type: `array`):

For Write articles: one entry per article. A topic is researched from several sources; a link is rewritten from that one page; your own source text (a press release, notes) is used as it is, with no search. Add "imageUrl" to any entry to give its WordPress post a featured image (and its reel a photo), and "imageAlt" to describe what that image shows (otherwise the AI writes a description without seeing the image). Plain text works too -- anything starting with http is treated as a link. Example: \[{"topic": "Teachers vote to strike over pay", "imageUrl": "https://example.com/photo.jpg", "imageAlt": "Teachers on a picket line outside a school"}, {"url": "https://example.com/news/story"}, {"topic": "New library opens", "sources": \[{"title": "Council press release", "text": "..."}]}]. A Find topics run gives each story a ready-made entry to paste here. Up to 20 per run.

## `defaultImageUrl` (type: `string`):

A link to an image you have the right to use, set as the featured image of every article a Find and write run posts to WordPress, and used as the photo in its reel. For Write articles, give each entry its own "imageUrl" instead. Images are never taken from the sources: those are other publishers' photos.

## `defaultImageAlt` (type: `string`):

What that image shows, in a sentence, e.g. "Pupils in a primary school classroom". Read aloud by screen readers and used by search engines. If left empty, the AI writes one from the article without seeing the image, so it may not match the picture.

## `articlesToWrite` (type: `integer`):

For Find and write: how many new stories to write per run. Stories written by an earlier run are skipped, and if a story's search finds nothing usable the next one is tried.

## `dateRange` (type: `string`):

How far back to look for stories. Find and write writes the top-ranked stories from this period that no earlier run has written. Automatic looks at about the last day or two. A wider range also allows older research sources, unless you set Maximum source age yourself.

## `newsQueries` (type: `array`):

Search terms run against Google News. Add when:1d to limit a search to the last day, or when:2d for slower-moving coverage.

## `newsLanguage` (type: `string`):

Google News language code, e.g. en, de, fr.

## `newsCountry` (type: `string`):

Google News country code, e.g. GB, US, IE.

## `homeCountry` (type: `string`):

Where your readers are, e.g. United Kingdom. Stories about this country count as domestic; stories comparing it with another country are promoted, and stories about another country's local affairs are demoted.

## `homePlaces` (type: `array`):

Other words that mark a story as domestic: the demonym, regions and major cities, e.g. british, scotland, london.

## `homeTlds` (type: `array`):

Domain endings of home-country outlets, e.g. uk, co.uk. An outlet with another country's ending is treated as foreign.

## `homeOutlets` (type: `array`):

Exact publisher names of your country's outlets, as Google News shows them, e.g. BBC News, The Guardian. A story from one of these counts as domestic even when its headline names no place.

## `assumeHome` (type: `string`):

Yes suits a language spoken mainly in one country (Romanian, Polish). No suits English, Spanish, French or German, where such stories are often foreign. Auto: worked out from your subject.

## `geographyMatters` (type: `string`):

No for a global subject such as a sport or a technology, where every story counts the same wherever it happens. Auto: worked out from your subject.

## `relevanceKeywords` (type: `array`):

Word stems that make a headline relevant, with the points each group adds. A stem matches any word containing it, so "educat" covers education, educational and educator. Example: \[{"points": 6, "stems": \["educat"]}, {"points": 4, "stems": \["school", "pupil"]}]

## `trustedOutlets` (type: `object`):

Bonus points for outlets you trust, matched against the publisher name. Example: {"bbc": 6, "guardian": 4}

## `maxTopics` (type: `integer`):

How many ranked stories to keep from one harvest, before near-duplicates are folded together.

## `sourceMaxAgeDays` (type: `integer`):

Only use sources published within this many days. Keeps news articles from being written from old coverage. Set 0 for evergreen topics, where older sources are fine.

## `model` (type: `string`):

Any OpenRouter model id. Leave empty for the default, google/gemini-2.5-flash, which wrote best in our comparison at about $0.005 per article. anthropic/claude-haiku-4.5 also writes well at roughly 3× the price. Reasoning models (e.g. deepseek/deepseek-v4-flash) can run into the free plan's 2,048-token reply limit.

## `siteName` (type: `string`):

Your publication's name. The writer is told it works for this site.

## `siteDescription` (type: `string`):

One line on what the site covers, e.g. "an education news site for parents and teachers".

## `englishVariant` (type: `string`):

British: organise, favour, 3 October 2026, per cent, headlines in sentence case. American: organize, favor, October 3, 2026, percent, headlines in title case. Automatic: American when the news country is the US, British otherwise.

## `citeSources` (type: `boolean`):

Mark quotes and specific figures with the outlet they came from, e.g. \[BBC]. Articles written from a single source never carry markers.

## `minWords` (type: `integer`):

Articles shorter than this are rejected and written again.

## `fixedHashtags` (type: `array`):

Your own hashtags, added to every reel caption and Facebook hashtag line, e.g. #yoursite. Leave empty for none of your own.

## `wpUrl` (type: `string`):

Your site's address, e.g. https://example.com. It must be reachable from the internet. A security plugin or firewall (e.g. Cloudflare) may need to allow requests from Apify.

## `wpUser` (type: `string`):

The login name of the account that will own the posts (not its display name).

## `wpAppPassword` (type: `string`):

Create one in WordPress under Users → Profile → Application Passwords. It is not your login password, can be revoked at any time, and is stored encrypted here. Spaces are fine.

## `wpStatus` (type: `string`):

Draft: saved for you to review and publish yourself. Publish: live straight away.

## `wpCategoryId` (type: `integer`):

Numeric ID of the category for new posts (shown in the address bar when editing the category). Leave empty for the site's default.

## `seoMetaPrefix` (type: `string`):

Where the SEO title, description and keywords are saved. hmt\_ for Head Meta Tags, rank_math\_ for Rank Math. The plugin must expose these fields to the REST API, or WordPress silently ignores them: check a post's page source the first time.

## `makeReel` (type: `boolean`):

Adds a reel for each article written, taking about a minute each. Runs with reels start with 4096 MB of memory instead of 1024 MB, so they cost more to run.

## `reelStyle` (type: `string`):

Rotate: each reel takes the next of the ten styles, and the order carries on across runs. Mixed presets: a varied plain look. Basic: one fixed plain look. Or pick one style for every reel. The styles are built on the photo: an article without one gets a mixed preset.

## `reelBrand` (type: `string`):

Your publication's name, shown in the reel's header. If left empty: the site name from Writing, else the site address.

## `reelSiteUrl` (type: `string`):

Shown on the closing card, where the reel sends viewers, e.g. yoursite.com. If left empty: your WordPress site's address, when one is set.

## `reelSection` (type: `string`):

A short label some styles show beside the name, e.g. Education or Sport. If left empty: News.

## `reelLogoUrl` (type: `string`):

Upload your logo, or give a link to it: a wide PNG with a transparent background works best. Shown large at the top of the closing card; without one, your publication's name goes there instead.

## `stateStoreName` (type: `string`):

Name of the key-value store that remembers written stories. Use a different name for each site you run, so their histories stay separate. Letters, digits and hyphens.

## Actor input object example

```json
{
  "mode": "findTopics",
  "subject": "UK education news",
  "articlesToWrite": 3,
  "dateRange": "auto",
  "assumeHome": "auto",
  "geographyMatters": "auto",
  "maxTopics": 50,
  "sourceMaxAgeDays": 7,
  "englishVariant": "auto",
  "citeSources": true,
  "minWords": 150,
  "wpStatus": "draft",
  "makeReel": false,
  "reelStyle": "rotate",
  "stateStoreName": "news-to-article-state"
}
```

# Actor output Schema

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

No description

## `settingsUsed` (type: `string`):

The discovery settings this run actually used, in input format, ready to copy into a run and adjust.

# 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 = {
    "subject": "UK education news"
};

// Run the Actor and wait for it to finish
const run = await client.actor("calin_a/article-reel-maker").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 = { "subject": "UK education news" }

# Run the Actor and wait for it to finish
run = client.actor("calin_a/article-reel-maker").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 '{
  "subject": "UK education news"
}' |
apify call calin_a/article-reel-maker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,calin_a/article-reel-maker"
        }
    }
}
```

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/e4Fo7pscquVK3tQew/builds/QQhIpvhC1rRlH78ZN/openapi.json
