# SEC Form 4 Scraper - Insider Trading (`datalayer/insider-trading-form4`) Actor

Form 4 carries a transaction code saying what actually happened, and almost nothing uses it — so an RSU vest gets published as an insider buy and the automatic tax withholding as a sale. This decodes all 19 codes, isolates genuine open-market purchases, and detects cluster buying.

- **URL**: https://apify.com/datalayer/insider-trading-form4.md
- **Developed by:** [Datalayer](https://apify.com/datalayer) (community)
- **Categories:** Other, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 filings

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

## SEC Insider Trading Scraper — Form 4 With the Codes Decoded

Most insider-trading data is wrong in the same way. Here is a real Apple filing
from 17 June 2026 (accession `0001140361-26-025622`), by Apple's SVP and
General Counsel:

| Code | Shares | Direction | Price |
|---|---|---|---|
| **M** | 30,104 | Acquired | — |
| **F** | 16,238 | Disposed | $296.42 |

A scraper that ignores the transaction code publishes this as *"insider
acquired 30,104 shares"* and *"insider sold 16,238 shares at $296.42."*

Both are wrong. **M** is an RSU exercise — no cash changed hands. **F** is
shares withheld automatically to pay the tax bill on that vest. Nobody made a
decision about Apple stock. The filing says nothing.

Only two of the nineteen Form 4 transaction codes involve someone choosing to
move money at the market price:

- **P** — bought on the open market
- **S** — sold on the open market

This Actor decodes all nineteen, reports **P** and **S** separately from
everything else, and tells you how many filings said nothing at all.

### What you get

**Real buys, isolated.** From a single day's market-wide sweep (11 Aug 2026):
57 filings contained an open-market trade, of which **3 were purchases and 54
were sales.** The largest purchase:

> **Harley-Davidson (HOG)** — Artie Starrs, President & CEO, bought **$258,941**
> on the open market, increasing his personal holding by **66.7%**.

That is the entire product. Three signals buried under fifty-four.

**Cluster-buy detection.** Two or more *separate* insiders buying on the open
market inside the same window — the most-studied insider signal in the
literature, and one that cannot be seen a filing at a time. Repeat filings by
the same person do not count.

**Holdings context.** `largestHoldingsChangePercent` sizes a trade against what
that person already owned. A $250k buy that lifts a position 67% is a different
event to one that lifts it 0.4%.

**10b5-1 flags.** Trades executed under a pre-arranged plan were scheduled
months earlier and carry no view on the price on the day. The form has carried
this checkbox since December 2022 and it is read straight off the filing.

**Seniority.** Officer titles are free text on the form (`SVP, GC and
Secretary`, `President & CEO`, `EVP and CFO`). They are normalised to `ceo`,
`cfo`, `c_suite`, `senior_officer`, `officer`, `ten_percent_owner`, `director`.

### Two modes

**By company** — pass tickers or CIKs:

```json
{ "tickers": ["AAPL", "NVDA", "HOG"], "maxFilingsPerCompany": 100 }
```

**Market-wide screen** — sweep every Form 4 filed and keep only real trades:

```json
{
  "scanAllFilings": true,
  "startDate": "2026-08-01",
  "endDate": "2026-08-11",
  "openMarketOnly": true,
  "excludePlannedTrades": true,
  "minTransactionValue": 100000
}
```

| Field | Default | Notes |
|---|---|---|
| `tickers` | `["AAPL"]` | Resolved to CIKs via SEC's own ticker file. |
| `ciks` | — | For registrants with no ticker. Apple is `320193`. |
| `scanAllFilings` | `false` | Whole-market sweep for the date range. |
| `startDate` / `endDate` | — | `YYYY-MM-DD`. |
| `openMarketOnly` | `false` | Keep only filings with a code P or S. |
| `excludePlannedTrades` | `false` | Drop 10b5-1 plan executions. |
| `minTransactionValue` | — | Dollar floor on the largest open-market trade. |
| `maxFilingsPerCompany` | `100` | ~1 year for most large caps. |
| `maxFilingsTotal` | `500` | Hard ceiling for the whole run. |
| `clusterWindowDays` | `30` | Window for cluster-buy detection. |
| `contactEmail` | — | Goes in the User-Agent, nowhere else. |

### Output

**`filing`** — one row per Form 4:

```json
{
  "type": "filing",
  "ticker": "HOG",
  "issuerName": "HARLEY-DAVIDSON, INC.",
  "insiderName": "Starrs Artie",
  "insiderTitle": "President & CEO",
  "seniority": "ceo",
  "hasOpenMarketBuy": true,
  "openMarketBuyValue": 258941,
  "openMarketSaleValue": 0,
  "largestHoldingsChangePercent": 66.7,
  "isCompensationOnly": false,
  "isPlanned10b5_1": false,
  "transactions": [
    { "transactionCode": "P", "transactionMeaning": "Open-market or private purchase",
      "category": "open_market_buy", "isInformative": true,
      "securityTitle": "Common Stock", "transactionDate": "2026-08-10",
      "shares": 10000, "pricePerShare": 25.8941, "value": 258941,
      "sharesOwnedBefore": 15000, "sharesOwnedAfter": 25000, "holdingsChangePercent": 66.7 }
  ]
}
```

**`issuer_summary`** — one row per company:

```json
{
  "type": "issuer_summary",
  "ticker": "AAPL",
  "filingsRead": 12,
  "compensationOnlyFilings": 5,
  "informativeFilings": 7,
  "distinctBuyers": 0,
  "distinctSellers": 5,
  "openMarketSaleValue": 111739341.32,
  "isClusterBuy": false,
  "topSeller": "LEVINSON ARTHUR D",
  "plannedTradeFilings": 5
}
```

### The transaction codes

| Code | Meaning | Counted as a trade? |
|---|---|---|
| P | Open-market or private purchase | **Yes** |
| S | Open-market or private sale | **Yes** |
| A | Grant or award from the issuer | No — compensation |
| M, C, X, O | Exercise or conversion of a derivative | No — no cash at market |
| F | Shares withheld for tax or exercise price | No — automatic |
| D | Disposition back to the issuer | No |
| G | Bona fide gift | No |
| I | Discretionary transaction in a benefit plan | No |
| E, H | Expiration of a derivative position | No |
| J, K, L, U, W, Z | Other, swap, small, tender, will, voting trust | No |

Nothing is discarded — every transaction is returned with its code and
category, so you can re-band them however you like.

### Reliability

- Official SEC endpoints only: `data.sec.gov`, `www.sec.gov/Archives`,
  `efts.sec.gov`. No login, no session, no scraping of rendered pages.
- The run stays under SEC's published 10 requests/second ceiling with a single
  serial pacer.
- A declared `User-Agent` with a contact address is sent on every request —
  SEC returns 403 to anything without one.
- One unparseable filing never fails the run; it lands in `RUN_SUMMARY` and the
  rest continue.

### Limits

- Form 4 XML exists from roughly 2003 onward. Older filings are scanned paper
  and are skipped with a recorded reason.
- EDGAR's full-text index refuses paging beyond ~10,000 hits, so market-wide
  sweeps walk one day at a time and warn if a day exceeds the cap.
- Officer seniority is derived from free text that companies write however they
  like. The raw `insiderTitle` is always on the row.
- Insiders have two business days to file, so `filedFor` (the trade date) and
  the filing date differ. Both are available.
- This is public regulatory data, returned as filed. It is not investment
  advice and no forecast is implied by any field.

# Actor input Schema

## `tickers` (type: `array`):

Stock tickers to pull insider filings for, for example AAPL, NVDA, HOG. Resolved to SEC CIKs automatically.

## `ciks` (type: `array`):

SEC CIK numbers, for companies with no ticker or where the ticker is ambiguous. Apple is 320193. Leading zeros optional.

## `startDate` (type: `string`):

Earliest filing date to include, YYYY-MM-DD. Leave empty for the most recent filings.

## `endDate` (type: `string`):

Latest filing date to include, YYYY-MM-DD.

## `openMarketOnly` (type: `boolean`):

Keep only filings containing a real purchase or sale at the market price (codes P and S). Drops grants, option exercises and tax withholding, which is most of what Form 4 traffic actually is.

## `excludePlannedTrades` (type: `boolean`):

Drop trades executed under a pre-arranged Rule 10b5-1 plan. Those were scheduled months earlier, so they carry no view on the price on the day.

## `minTransactionValue` (type: `integer`):

Drop filings whose largest open-market trade is below this dollar value.

## `scanAllFilings` (type: `boolean`):

Ignore the ticker list and sweep every Form 4 filed across the whole market for the date range. Combine with Open-market trades only to screen the entire market for real insider buying.

## `includeTransactions` (type: `boolean`):

Attach every individual transaction to its filing row, each with its decoded code. Turn off for a slimmer output.

## `includeIssuerSummary` (type: `boolean`):

One summary row per company: distinct buyers and sellers, net open-market value, cluster-buy detection and how many filings were compensation only.

## `clusterWindowDays` (type: `integer`):

Days within which separate insiders buying counts as a cluster buy. Thirty days is the convention in the research literature.

## `maxFilingsPerCompany` (type: `integer`):

How far back to read for each company. Large caps file Form 4s constantly, so 100 covers roughly a year for most.

## `maxFilingsTotal` (type: `integer`):

Hard ceiling across every company, so a wide market sweep cannot run away.

## `contactEmail` (type: `string`):

SEC asks automated callers to identify themselves. Your email goes in the User-Agent header and nowhere else. Optional but courteous, and it keeps you off shared throttling.

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

Optional. SEC allows 10 requests per second per IP and this Actor stays under that, so a proxy is only needed if you hit shared throttling.

## Actor input object example

```json
{
  "tickers": [
    "AAPL",
    "NVDA"
  ],
  "openMarketOnly": false,
  "excludePlannedTrades": false,
  "scanAllFilings": false,
  "includeTransactions": true,
  "includeIssuerSummary": true,
  "clusterWindowDays": 30,
  "maxFilingsPerCompany": 100,
  "maxFilingsTotal": 500,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `trades` (type: `string`):

One row per Form 4, with real buys and sales separated from compensation.

## `companies` (type: `string`):

Per-company totals, distinct buyers and sellers, and cluster-buy detection.

## `all` (type: `string`):

Filings and company summaries together, with the full transaction rows.

## `csv` (type: `string`):

Everything as a CSV download.

## `runSummary` (type: `string`):

Counts, plus any ticker or filing that could not be read.

# 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 = {
    "tickers": [
        "AAPL",
        "NVDA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datalayer/insider-trading-form4").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 = { "tickers": [
        "AAPL",
        "NVDA",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("datalayer/insider-trading-form4").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 '{
  "tickers": [
    "AAPL",
    "NVDA"
  ]
}' |
apify call datalayer/insider-trading-form4 --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datalayer/insider-trading-form4"
        }
    }
}

```

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/u7nCVVCl5U7gzBtc9/builds/0DaDgIz7YZqDY6KMP/openapi.json
