# Trade Press Scraper: APAC Advertising & Marketing News (`lexac94/trade-press-scraper`) Actor

Scrape Marketing-Interactive articles by date range and Boolean query. Get headline, date, author, tags, video and outbound links as JSON, CSV or Excel.

- **URL**: https://apify.com/lexac94/trade-press-scraper.md
- **Developed by:** [Lexa N](https://apify.com/lexac94) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $9.00 / 1,000 articles

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

## Trade Press Scraper

Turn advertising and marketing trade press into structured data. Pick a date
range, optionally narrow it with a Boolean query, and get one row per article
with the headline, publish time, author, section, tags, summary, campaign
credits where the publication prints them, and every video, social post and
outbound link the article points to.

Covers two publications, in one dataset with the same columns:

- **Marketing-Interactive** (marketing-interactive.com): APAC marketing and
  advertising news for Singapore, Malaysia, Hong Kong, Indonesia, the
  Philippines, Thailand and Australia, archive back to 2007.
- **Campaign Brief Asia** (campaignbriefasia.com): campaign launches and
  agency news across Asia and the Middle East, archive back to 2019. About
  half its articles end with a credits block (client, agency, production
  house, media agency, director), which comes back as separate columns.

### What you can use it for

- **New business and competitive tracking.** Agency appointments, account
  wins, pitches and reviews for the brands and agencies you care about.
- **Campaign libraries.** Every campaign a brand or agency ran in a period,
  with links to the films on YouTube or Vimeo.
- **Who made what.** Which agencies, production houses and media agencies a
  brand worked with, from the published campaign credits.
- **Market and media monitoring.** Mentions of brands, agencies, people or
  topics across APAC trade press, on a schedule.
- **Research.** How coverage of a topic (retail media, AI, sustainability)
  moved over months or years.

### How it works

1. Choose the publications and a date range ("Published from" accepts a date
   or a range like `2 years`).
2. Optionally write a Boolean query. Matching against **headline and tags**
   checks every article before downloading it, so only matches are fetched.
   (Campaign Brief Asia has no tags, so there the headline is checked.)
   Matching against **full article text** downloads everything in the range
   and checks the body too, which catches names that only appear in campaign
   credits.
3. Run it. Each article becomes one row. Download as JSON, CSV or Excel, or
   pull it through the Apify API.

### Writing a query

| Write | Matches |
|---|---|
| `Grab OR Gojek` | either word, any case, as a whole word |
| `Grab AND campaign` or `Grab campaign` | both words |
| `NOT Malaysia` | articles without the word |
| `"Health Promotion Board"` | the exact phrase |
| `appoint*` | appoint, appoints, appointed, appointment |
| `/\bMOM\b/` | case-sensitive regular expression |
| `( ... )` | grouping |

`NOT` binds tightest, then `AND`, then `OR`, so `a OR b AND c` means
`a OR (b AND c)`. Use brackets when in doubt. Operators must be uppercase.

Example queries:

```
(appoint* OR pitch* OR "account" OR review*) AND (Ogilvy OR Publicis OR Dentsu)
```

```
(Grab OR Gojek OR foodpanda) AND (campaign* OR film OR launch*)
```

```
(CPF OR HPB OR "Health Promotion Board" OR govt OR ministr*)
AND NOT (Malaysia OR Indonesia)
```

Each row's `matched_terms` lists which parts of the query it matched, so you
can see why an article was included. A query with a syntax error stops the run
before anything is fetched, with a message saying what is wrong.

**Tip:** headlines often use informal names ("govt", "Health ministry") and
lowercase acronyms ("MoH"). Include the variants, or switch to full-text
matching.

### Input

| Field | What it does |
|---|---|
| Publications | Which trade publications to collect from. Default: both. |
| Published from / to | Date range, Singapore time. Default: the last 7 days. |
| Boolean query | Optional filter. Empty keeps everything in the range. |
| Match the query against | Headline and tags (fast) or full article text. |
| Include article text | Off by default. See below. |
| Max articles | Stop after this many, newest first. 0 means no limit. |
| Article URLs | Fetch specific articles instead of a date range. |
| Max pages per minute | Default 20, maximum 60. |
| Proxy | Apify datacenter proxy by default. |

#### Article text

By default each row carries the article's metadata, credits and links, and
`body_text` is empty. The body is still read, so word counts, credits, links,
videos and full-text query matching all work.

The publication's own boilerplate inside the article (related headlines,
"See more" links, event ads) is removed from the text, so a full-text query
doesn't match an article because of a headline it merely links to.

Turn on **Include article text** to receive the full text as well. Article
text belongs to its publisher: use it for your own research and analysis, and
don't republish it.

### Output

One row per article. A real row from Marketing-Interactive:

```json
{
  "site": "marketing-interactive",
  "url": "https://www.marketing-interactive.com/cpf-gets-weird-to-show-retirement-planning-can-be-easier",
  "title": "CPF gets weird to show retirement planning can be easier",
  "published_at": "2026-10-01T09:21:03+08:00",
  "author": "A'bidah Zaid Shirbeeni",
  "author_url": "https://www.marketing-interactive.com/authors/a-bidah-zaid-shirbeeni",
  "section": "News",
  "tags": ["CPF Board", "MoneySense", "GOVT VCCP", "retirement planning",
           "CPF campaign", "Starcom Worldwide", "Salihin Ramli", "Gabe Chen"],
  "teaser": "CPF Board and MoneySense are taking a lighter approach to retirement planning, using fortune tellers, fortune cats and an overload of financial information to show Singaporeans that preparing for the future does not have to be complicated.",
  "word_count": 534,
  "video_urls": [
    "https://www.youtube.com/watch?v=QQ16ojXd3GY",
    "https://www.youtube.com/watch?v=dDSGLut-VD8",
    "https://www.youtube.com/watch?v=EvYVOA9Jl8k"
  ],
  "social_urls": [],
  "external_links": [],
  "internal_links": [
    "https://www.marketing-interactive.com/cpf-concludes-integrated-marketing-pitch",
    "https://www.marketing-interactive.com/how-public-sector-campaigns-in-sg-have-become-increasingly-un-government"
  ],
  "image_url": "https://marketing-interactive-assets.b-cdn.net/article_images/cpf-gets-weird-to-show-retirement-planning-can-be-easier/1790817651_CPF%20%281%29.jpg",
  "matched_terms": [],
  "body_text": null,
  "scraped_at": "2026-10-08T12:26:18.995Z",
  "error": null
}
```

(Tags and internal links shortened here.)

A real row from Campaign Brief Asia, showing the credit fields:

```json
{
  "site": "campaign-brief-asia",
  "url": "https://campaignbriefasia.com/2026/10/07/ocbc-and-govt-vccp-singapore-show-how-ai-can-make-anyone-look-like-a-scammer/",
  "title": "OCBC and GOVT VCCP Singapore show how AI can make anyone look like a scammer",
  "published_at": "2026-10-07T08:28:39+08:00",
  "author": "Adam Shaw",
  "section": "Agencies",
  "credit_client": "OCBC",
  "credit_agency": "GOVT VCCP",
  "credit_production": "ROLLA Productions",
  "credit_media": "Wavemaker",
  "credits": [
    {"group": null, "role": "Client", "name": "OCBC"},
    {"group": null, "role": "Agency", "name": "GOVT VCCP"},
    {"group": null, "role": "Media Partner", "name": "Wavemaker"},
    {"group": null, "role": "Film Director", "name": "Jake Nam"},
    {"group": null, "role": "Film Production", "name": "ROLLA Productions"}
  ],
  "video_urls": ["https://www.youtube.com/watch?v=-c9b1LjobcM"]
}
```

(Other fields left out here.)

| Field | Description |
|---|---|
| `site` | Publication key: `marketing-interactive` or `campaign-brief-asia`. |
| `url` | Canonical article URL. |
| `title` | Headline. |
| `published_at` | Publish time, ISO 8601, Singapore time (+08:00). |
| `author`, `author_url` | Byline and author page. |
| `section` | Section, e.g. News, Agencies, Media, Opinions. |
| `tags` | The publication's own keywords for the article (Marketing-Interactive only). |
| `teaser` | The article's summary line. |
| `credit_client`, `credit_agency`, `credit_production`, `credit_media` | Company names from the credits block, by role. Several names are separated by `; `. Empty when the article has no credits or no line with that role. |
| `credits` | Every line of the credits block as `{group, role, name}`. `group` is the company or film heading the line sits under, when there is one. |
| `word_count` | Length of the article body. |
| `video_urls` | YouTube and Vimeo links, from embeds and links. |
| `social_urls` | Instagram, TikTok, Facebook, X, LinkedIn and Threads posts. |
| `external_links` | Other outbound links: brands, agencies, campaign sites, other news. |
| `internal_links` | Links to the publication's own pages. |
| `image_url` | The article's main image. |
| `matched_terms` | Query terms this article matched. Empty without a query. |
| `body_text` | Full article text, only with Include article text on. |
| `error` | Set on rows that could not be collected, with the reason. |

Rows with `error` set keep the same columns, so exports line up. Filter them
out by keeping rows where `error` is empty.

#### How credits are read

Credits come only from the article's labelled credits block, never guessed
from the text. A line such as `Production House: Freeflow Productions` fills
`credit_production`; lines naming people (`Director: Peggy Goh`, `Head of
Production: ...`) stay in `credits` only. Credits are written by the agencies,
so labels vary: when an agency appears only as a heading over its staff, or
only in the headline, `credit_agency` stays empty and the name is in
`credits` (as `group`) or the title. Marketing-Interactive writes credits into
the article prose, so its credit fields are empty; use full-text matching to
find names there.

### How long does it take?

Pages are fetched at 20 per minute by default, which keeps the run gentle on
the publication and clear of its rate limits.

- A week of both publications (about 175 articles): about 9 minutes.
- Two years filtered by headline and tags: usually a few hundred articles,
  under half an hour.
- Two years unfiltered: around 9 hours for Marketing-Interactive (about
  10,300 articles), 3 hours for Campaign Brief Asia (about 3,700). Narrow the
  query or the date range, or raise the speed towards 60 per minute.

For runs longer than an hour, check the run's **Timeout** in the run options.
A run that reaches its timeout stops and keeps what it collected so far.

### Pricing

Pay per event. See the Pricing tab for current prices.

- **Article:** each article in your results.
- **Article text:** an add-on per article, only when Include article text is on.
- **Article scanned:** only with full-text matching, for each article that was
  downloaded and checked against your query but didn't match. Same price as
  an article, so every article read costs the same whether it matches or not.
- **Actor start:** once per run.

Pages that fail are never charged. With headline-and-tags matching,
non-matching articles are never downloaded, so they cost nothing.

As a guide, at the time of writing:

- A week of both publications (about 175 articles): about $1.60.
- Two years of Marketing-Interactive (about 10,300 articles): about $93, or
  about $196 with article text on every row.
- Two years of Campaign Brief Asia (about 3,700 articles): about $34. Five
  years (about 8,600): about $78.
- A full-text search reads every article in the range, so it costs the same
  as pulling them all, plus article text for the matches if you turn it on.
- A headline-and-tags search only pays for its matches: one matching 400
  articles over two years costs about $4.

Set a maximum cost per run in Apify and the run stops when it is reached. Each
run's final status lists what was charged.

### FAQ

**Does it get around paywalls?**
No. It reads publicly available pages only, and only publications whose
articles are free to read are supported.

**Is scraping these sites allowed?**
The actor reads public pages, follows each publication's robots.txt, and is
rate-limited. You are responsible for how you use the data, including the
publisher's terms and copyright. If in doubt, take legal advice.

**Why did my query return fewer articles than expected?**
With headline-and-tags matching, an article only counts if your terms appear
in its headline or tags. Add informal variants, or switch to full-text
matching.

**Why are the credit columns empty on some rows?**
Either the article has no credits block (about half of Campaign Brief Asia
articles don't, and Marketing-Interactive doesn't use one), or no line in it
carries that role. Check `credits` for the full block.

**Why are some rows errors?**
A page that stays unavailable after several retries becomes an error row with
the reason, so nothing goes missing silently. Rows saying the site is
throttling mean the speed was too high: lower Max pages per minute.

**Can I schedule it?**
Yes. Save a task with a relative date such as `7 days` and schedule it weekly
in Apify.

### Limitations

- Two publications so far: Marketing-Interactive and Campaign Brief Asia.
- Credit columns are filled only from a labelled credits block. Marketing-
  Interactive writes credits into the article prose, so finding them there
  needs full-text matching.
- The headline used for headline matching is the one in the publication's
  sitemap or feed, which very occasionally differs slightly from the one on
  the page.
- Speed is capped at 60 pages a minute to protect the publication.

# Actor input Schema

## `sites` (type: `array`):

Trade publications to collect from. Marketing-Interactive covers Singapore, Malaysia, Hong Kong, Indonesia, the Philippines, Thailand, Australia and APAC-wide news. Campaign Brief Asia covers campaigns and agency news across Asia and the Middle East, and about half its articles list campaign credits (client, agency, production house, media), returned as separate columns.

## `dateFrom` (type: `string`):

Earliest publication date to include (Singapore time). Pick a date, or a relative range such as "7 days", "6 months" or "2 years" back from today. Default: the last 7 days.

## `dateTo` (type: `string`):

Latest publication date to include, inclusive (Singapore time). Leave empty for today.

## `query` (type: `string`):

Combine terms with AND, OR, NOT (uppercase) and brackets. Words match whole words in any case. Use "quotes" for exact phrases and \* as a wildcard (appoint\* matches appoints, appointed, appointment). For case-sensitive acronyms use a regular expression between slashes, e.g. /\bMOM\b/. Example: (Grab OR Gojek) AND (campaign\* OR agency OR pitch\*)

## `queryScope` (type: `string`):

Headline and tags is fast and cheap: articles are checked before they are downloaded, so only matches are fetched. (Campaign Brief Asia has no tags, so there it checks the headline.) Full article text downloads every article in the date range and checks the headline, tags, summary and body, including any credits block. Use it when the names you need appear only in the body, such as a production house or director.

## `includeFullText` (type: `boolean`):

Off: each row has the headline, date, author, section, tags, summary, campaign credits (where published), word count, and the video, social and outbound links in the article. On: rows also include the full article text. Article text belongs to its publisher; use it for your own research and analysis, and don't republish it.

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

Stop after this many articles, newest first. 0 means no limit. Set a small number for a first test.

## `articleUrls` (type: `array`):

Full URLs of articles on a supported publication, one per line.

## `maxRequestsPerMinute` (type: `integer`):

How fast pages are fetched. The default of 20 per minute is gentle on the publication and avoids rate limits; at 20 per minute, 1,000 articles take about 50 minutes. The maximum is 60. If the run's status message mentions throttle pauses, lower it.

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

Apify's datacenter proxy works for both publications. If a run fails with error rows mentioning Cloudflare, switch to the RESIDENTIAL proxy group.

## Actor input object example

```json
{
  "sites": [
    "marketing-interactive",
    "campaign-brief-asia"
  ],
  "dateFrom": "7 days",
  "queryScope": "headline_tags",
  "includeFullText": false,
  "maxItems": 50,
  "articleUrls": [],
  "maxRequestsPerMinute": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "sites": [
        "marketing-interactive",
        "campaign-brief-asia"
    ],
    "dateFrom": "7 days",
    "query": "",
    "maxItems": 50,
    "maxRequestsPerMinute": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lexac94/trade-press-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 = {
    "sites": [
        "marketing-interactive",
        "campaign-brief-asia",
    ],
    "dateFrom": "7 days",
    "query": "",
    "maxItems": 50,
    "maxRequestsPerMinute": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lexac94/trade-press-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 '{
  "sites": [
    "marketing-interactive",
    "campaign-brief-asia"
  ],
  "dateFrom": "7 days",
  "query": "",
  "maxItems": 50,
  "maxRequestsPerMinute": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lexac94/trade-press-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lexac94/trade-press-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/IJeqwYiAknAdUCGHm/builds/zBCquRmtDu3rNwfDx/openapi.json
