# SEC Form 4 Insider Trades by Ticker (`codecraftco/sec-insider-trades`) Actor

Parsed insider transactions from SEC Form 4 filings for any US ticker: buys, sales, grants, option exercises, 10b5-1 flags, with reporter role and post-transaction holdings.

- **URL**: https://apify.com/codecraftco/sec-insider-trades.md
- **Developed by:** [Code Craft Colorado](https://apify.com/codecraftco) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 insider transactions

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/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

## SEC Form 4 Insider Trades by Ticker

Get every insider transaction reported to the SEC for any US-listed company, parsed into one
row per transaction. Give it a list of tickers and it returns buys, sales, grants, option
exercises, tax withholdings and gifts straight from the Form 4 filings on EDGAR, with the
insider's name and role, the price, the share count, the shares owned after the trade, whether
it was made under a Rule 10b5-1 plan, the footnotes the filer attached, and a link back to the
filing. Every field is a real field from the filing; nothing is estimated or inferred.

It is built to be left running. The data comes from the SEC's own EDGAR endpoints over plain
HTTP: no API key, no login, no browser, no proxies. The client identifies itself as the SEC's
fair-access policy requires, stays under the SEC's request-rate limit, and backs off when the
SEC asks it to. A Form 4 accepted by EDGAR is normally available here within minutes of filing.

### At a glance

Three real rows from one run for `AAPL`: a sale, an RSU settlement, and the shares withheld
for tax on that settlement.

| transactionDate | transactionCode | securityTitle | shares | pricePerShare | sharesOwnedFollowing |
| --- | --- | --- | --- | --- | --- |
| 2026-09-22 | S | Common Stock | 2399 | 340.06 | 44391 |
| 2026-09-15 | M | Restricted Stock Unit | 30104 | null | 180624 |
| 2026-09-15 | F | Common Stock | 16228 | 331.34 | 46790 |

### What data does it extract?

Each row is one transaction from one Form 4 (or, if you ask for them, Form 4/A) filing. A
filing with three transactions produces three rows that share the same filing-level fields.
Holdings-only entries, where a position is reported without a transaction, are skipped.

**Issuer and request**

- `ticker`: the ticker you asked for.
- `issuerCik`, `issuerName`: the company as printed in the filing.

**Who filed**

- `reporterCik`, `reporterName`: the primary reporting owner, named as EDGAR prints it
  (surname first, for example `Newstead Jennifer`).
- `isDirector`, `isOfficer`, `isTenPercentOwner`, `isOther`: the relationship boxes on the
  form. `null` when the filer left a box out entirely.
- `officerTitle`: the officer's title, for example `SVP, GC and Government Affairs`.
- `coReporters`: names of any additional reporting owners on a joint filing. Empty otherwise.

**The filing**

- `filingDate`: the date the form was filed (`YYYY-MM-DD`). Date filters apply to this field.
- `periodOfReport`: the date of the earliest transaction in the filing.
- `accessionNumber`: EDGAR's unique filing identifier.
- `form`: `4` or `4/A`.
- `sourceUrl`: the filing's index page on EDGAR, where you can open the original document.

**The transaction**

- `isDerivative`: `false` for Table I (common stock and other non-derivative securities),
  `true` for Table II (options, RSUs, warrants and other derivative securities).
- `securityTitle`: what was traded, for example `Common Stock` or `Restricted Stock Unit`.
- `transactionDate`, `deemedExecutionDate`: when the transaction happened, and the deemed
  execution date if one was reported.
- `transactionFormType`: the form type recorded against the transaction itself.
- `transactionCode`, `transactionCodeMeaning`: the SEC's one-letter code and its meaning in
  plain English (see the table below).
- `equitySwapInvolved`: whether the filer marked the transaction as involving an equity swap.
- `acquiredDisposed`: `A` for acquired, `D` for disposed.
- `shares`, `pricePerShare`: the amount and the price per share. Price is `null` when the
  filer did not report one, which is common for grants and RSU settlements.
- `sharesOwnedFollowing`: shares owned after the transaction, as reported.
- `ownership`, `indirectOwnershipNature`: `D` for direct, `I` for indirect, and for indirect
  holdings the nature of the holding, for example a trust.

**Derivative details (Table II rows only, `null` otherwise)**

- `conversionOrExercisePrice`: the strike or conversion price.
- `exerciseDate`, `expirationDate`: when the derivative becomes exercisable and when it expires.
- `underlyingSecurityTitle`, `underlyingShares`: the security the derivative converts into
  and how many shares of it.

**Context**

- `aff10b5One`: `true` when the filer checked the box stating the transactions were made under
  a Rule 10b5-1 trading plan. It is a filing-level box, so every row from that filing carries
  the same value.
- `footnotes`: the full text of every footnote attached to this transaction, in the order they
  are referenced. Filers often put the real detail here: weighted-average prices, vesting
  schedules, the plan adoption date.

### Form 4 transaction codes

`transactionCode` is the SEC's one-letter code for what kind of transaction took place. The
actor fills `transactionCodeMeaning` from this table, and the `transactionCodes` input accepts
any of these letters as a filter.

| Code | Meaning |
| --- | --- |
| `P` | Open market or private purchase |
| `S` | Open market or private sale |
| `A` | Grant, award or other acquisition |
| `D` | Disposition to the issuer |
| `F` | Payment of exercise price or tax liability by delivering or withholding securities |
| `M` | Exercise or conversion of derivative security |
| `G` | Gift |
| `C` | Conversion of derivative security |
| `J` | Other acquisition or disposition |
| `W` | Acquisition or disposition by will or the laws of descent and distribution |
| `X` | Exercise of in-the-money or at-the-money derivative security |
| `I` | Discretionary transaction |
| `L` | Small acquisition under Rule 16a-6 |
| `U` | Disposition pursuant to a tender of shares in a change of control transaction |
| `Z` | Deposit into or withdrawal from voting trust |
| `V` | Transaction voluntarily reported earlier than required |
| `K` | Transaction in equity swap or similar instrument |
| `H` | Expiration or cancellation of long derivative position with value received |
| `E` | Expiration of short derivative position |
| `O` | Exercise of out-of-the-money derivative security |

For questions about insider sentiment, `P` and `S` are the codes that matter: they are the
insider's own open-market decisions. `A`, `M` and `F` usually describe compensation mechanics
(a grant, its vesting or exercise, and the shares withheld to cover tax). A code not in this
table gets a `null` meaning.

Two more one-letter fields appear on every row:

| Field | Value | Meaning |
| --- | --- | --- |
| `acquiredDisposed` | `A` | Securities were acquired |
| `acquiredDisposed` | `D` | Securities were disposed of |
| `ownership` | `D` | Held directly by the reporting owner |
| `ownership` | `I` | Held indirectly, for example through a trust; see `indirectOwnershipNature` |

### Input

| Field | Type | Default | What it does | When to use it |
| --- | --- | --- | --- | --- |
| `tickers` | array of strings | required | Tickers to fetch, for example `["AAPL", "MSFT"]`. Each is resolved to an SEC CIK using the SEC's own ticker file. | Always. |
| `startDate` | `YYYY-MM-DD` | last 30 days | Only include filings filed on or after this date. With no dates and no count, the actor returns the last 30 days. | Backfills and "since January" questions. |
| `endDate` | `YYYY-MM-DD` | none | Only include filings filed on or before this date. | Reproducible historical windows. |
| `maxFilingsPerTicker` | integer | none | Newest filings first; stop after this many per ticker. Applies only when set, and combines with dates to cap a window. A filing usually holds one to a few transactions. | A quick look at the latest few, or a bounded backfill. |
| `includeAmendments` | boolean | `false` | Also process Form 4/A amendments. Amended rows carry `form: "4/A"`. | When you need corrections to earlier filings. |
| `includeDerivatives` | boolean | `true` | Include Table II rows: options, RSUs, warrants and other derivatives. | Turn off to see only common-stock movements. |
| `transactionCodes` | array of codes | all | Keep only transactions with these codes. | `["P", "S"]` for open-market buys and sells. |

Both date filters compare against `filingDate`, not the transaction date, because that is what
EDGAR indexes. Tickers are upper-cased before lookup, so `aapl` and `AAPL` are the same.

**The latest activity for a watchlist**

```json
{
    "tickers": ["AAPL", "MSFT", "NVDA"]
}
```

**Open-market purchases only, this year**

```json
{
    "tickers": ["NVDA"],
    "transactionCodes": ["P"],
    "startDate": "2026-01-01"
}
```

**A full backfill including amendments, common stock only**

```json
{
    "tickers": ["AAPL"],
    "startDate": "2020-01-01",
    "endDate": "2025-12-31",
    "maxFilingsPerTicker": 1000,
    "includeAmendments": true,
    "includeDerivatives": false
}
```

The actor fetches roughly five filings per second, so 1,000 filings take three to four
minutes. The default 30-day window is a handful of filings for most companies and finishes in seconds.

### Output example

One row from the run above, with the derivative-only fields (all `null` on a common-stock row)
removed for readability:

```json
{
    "ticker": "AAPL",
    "issuerCik": "0000320193",
    "issuerName": "Apple Inc.",
    "reporterCik": "0001780525",
    "reporterName": "Newstead Jennifer",
    "coReporters": [],
    "isDirector": false,
    "isOfficer": true,
    "isTenPercentOwner": false,
    "isOther": false,
    "officerTitle": "SVP, GC and Government Affairs",
    "filingDate": "2026-09-24",
    "periodOfReport": "2026-09-22",
    "accessionNumber": "0001140361-26-037584",
    "form": "4",
    "isDerivative": false,
    "securityTitle": "Common Stock",
    "transactionDate": "2026-09-22",
    "transactionFormType": "4",
    "transactionCode": "S",
    "transactionCodeMeaning": "Open market or private sale",
    "equitySwapInvolved": false,
    "acquiredDisposed": "D",
    "shares": 2399.0,
    "pricePerShare": 340.06,
    "sharesOwnedFollowing": 44391.0,
    "ownership": "D",
    "footnotes": [
        "This transaction was made pursuant to a Rule 10b5-1 trading plan adopted by the reporting person on May 5, 2026."
    ],
    "aff10b5One": true,
    "sourceUrl": "https://www.sec.gov/Archives/edgar/data/320193/000114036126037584/0001140361-26-037584-index.htm"
}
```

A Table II row has the same fields plus the derivative details. The RSU settlement from the
same run, trimmed to the fields that differ:

```json
{
    "isDerivative": true,
    "securityTitle": "Restricted Stock Unit",
    "transactionCode": "M",
    "acquiredDisposed": "D",
    "shares": 30104.0,
    "pricePerShare": null,
    "sharesOwnedFollowing": 180624.0,
    "underlyingSecurityTitle": "Common Stock",
    "underlyingShares": 30104.0
}
```

Rows are written to the run's default dataset as they are produced, so you can start reading
before the run finishes. Download them from Apify Console or the API as JSON, JSONL, CSV,
Excel or XML. The dataset's **Transactions** view shows the fields most people want first:
insider, title, date, code, shares, price, holdings after, and a link to the filing.

### Errors and edge cases

When something cannot be processed, the actor records it and carries on. Failures are written
to a record named `ERRORS` in the run's default key-value store, as a JSON array with one
entry per failure. Each entry has the `ticker` and a plain-text `error`; failures on a specific
filing also carry the `accessionNumber` and `sourceUrl`. The record exists only when something
failed, and the run's status message reports the count of transactions, filings and errors. No
row is charged for a failure.

- **Ticker not in the SEC registry.** Tickers are resolved with the SEC's own
  `company_tickers.json`. Some ETFs and foreign listings are not in it. The ticker is recorded
  as `Ticker not found in SEC registry` and the run moves on.
- **A filing that cannot be fetched or parsed.** If EDGAR returns an error for the filing's XML
  document, or the document is not a well-formed ownership document, that filing is skipped
  and recorded with its accession number and link. Other filings are unaffected.
- **Transient EDGAR errors.** Server errors and connection failures are retried with increasing
  delays before a filing is given up on.
- **SEC throttling.** The SEC caps automated traffic at 10 requests per second; the actor runs
  at about half that by default. If the SEC still answers with its throttle response, the actor
  pauses (30 seconds the first time, escalating to 10 minutes for repeated throttles in a row),
  halves its request rate for the rest of the run, retries, and only creeps back toward the
  normal rate after a stretch of successful requests. A throttled run finishes late rather than
  failing. If the SEC keeps refusing requests for a cumulative 20 minutes in one run, the run
  stops with a status message saying so; every row already delivered is kept.
- **Run charge limit.** If you set a maximum charge on the run and it is reached, the actor
  stops pushing rows and finishes normally with the rows delivered so far.

### How much does it cost?

The billable unit is one dataset row, and one row is one transaction from one Form 4 filing.
Apply the filters (`transactionCodes`, `includeDerivatives`, the date range,
`maxFilingsPerTicker`) and you pay only for the rows that pass them.

There are no other events beyond Apify's standard actor start. Resolving tickers, reading the
EDGAR submissions index, fetching filings, pausing for the SEC, and writing the `ERRORS`
record are not charged. Filings that fail to parse, tickers that cannot be resolved, and
filings that contain only holdings produce no rows and cost nothing.

Current per-row pricing is on the Pricing tab of this page.

### Use cases

- Watch a portfolio for insider buying and selling and push new rows to a dashboard or a
  chat channel on a schedule.
- Alert on open-market purchases (`transactionCodes: ["P"]`) by officers and directors, the
  signal most insider-activity strategies are built on.
- Backfill a database of insider activity with `startDate` and `maxFilingsPerTicker: 1000`,
  then run daily with the defaults to keep it current.
- Separate planned selling from discretionary selling with `aff10b5One`, and read the plan
  adoption date from `footnotes`.
- Track how an executive's stake changes over time with `sharesOwnedFollowing`.
- Give an AI agent a reliable answer to "what have insiders at this company been doing lately?"
  with a filing link for every claim.

### Run it on a schedule, from the API, or from an agent

The actor runs the same way from a saved task on a Console schedule, from the Apify API or
the JavaScript and Python clients, and as a tool through Apify's MCP server, so an AI agent
can call it directly. The input JSON is identical in every case, and the results are in the
run's dataset whichever way it was started.

### Related actors

- [SEC 13F Holdings by Fund with Quarterly Changes](https://apify.com/codecraftco/sec-13f-holdings):
  every position in a fund's 13F filing with the change from the prior quarter, in dollars.
- [SEC 8-K Filings by Ticker with Item Codes](https://apify.com/codecraftco/sec-8k-filings):
  8-K filings with item codes and titles, exhibits, and optional extracted text.
- [Wayback Machine Snapshots and Archived Page Content](https://apify.com/codecraftco/wayback-snapshots):
  every Wayback Machine capture of a URL, host, or domain, with optional archived page text.

All four run against official public APIs with no proxies or credentials.

### FAQ

**Is this legal?** Yes. Form 4 filings are public records that the SEC publishes for anyone to
read. This actor uses the SEC's official EDGAR endpoints, identifies itself with the company
name and a contact address as the SEC's fair-access policy requires, and stays under the SEC's
published request-rate limit.

**How current is the data?** EDGAR's submissions feed updates in near real time. A Form 4
accepted this afternoon is usually returned by the next run within minutes. `filingDate`
typically trails `transactionDate` by a day or two, which is the filing deadline insiders work
to.

**Why are some fields null?** Filers sometimes replace a value with a footnote, for example
when a price is a weighted average or an exercise date depends on vesting, and grants and RSU
settlements often have no price at all. The footnote text is in `footnotes`, so nothing is
lost. Derivative-only fields are always `null` on common-stock rows.

**Why is `isDirector` sometimes `false` and sometimes `null`?** `false` means the filer marked
"no". `null` means the filer left that element out of the filing altogether, which EDGAR
permits. Treat both as "not a director" unless the distinction matters to you.

**Does `aff10b5One` apply to each transaction individually?** No. It is a single checkbox on
the filing, so every row from that filing carries the same value, including grant, exercise and
tax-withholding rows that are not themselves trades. Read the `footnotes` on a row to see which
transactions the filer attributes to the plan.

**A ticker returned nothing.** Check the run's `ERRORS` record in the key-value store. Tickers
not in the SEC's registry are reported there. If the ticker resolved but no rows came back, the
company may have no Form 4 filings in your date range, or every filing in range was filtered
out by `transactionCodes` or `includeDerivatives`.

**How do I avoid double-counting amended filings?** Leave `includeAmendments` off unless you
need corrections. When it is on, amended rows carry `form: "4/A"` and their own
`accessionNumber`, so you can prefer the amendment and drop the original in your own
processing.

**Can I look up by CIK or company name instead of ticker?** Not currently. The input is a
list of tickers, resolved through the SEC's ticker file. Companies without a ticker in that
file cannot be fetched.

**What happens if the SEC rate-limits the run?** The actor pauses, slows down and retries, so
the run finishes late rather than failing; after 20 minutes of cumulative cooldown it stops
with a status message and keeps every row already delivered. See "Errors and edge cases".

**Something is missing or wrong?** Open an issue on the actor's Issues tab. Include the
`accessionNumber` or `sourceUrl` of the filing if the problem is with a specific row.

# Actor input Schema

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

Stock tickers to fetch insider transactions for, e.g. AAPL, MSFT. Resolved to SEC CIKs automatically.

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

Only include filings filed on or after this date (YYYY-MM-DD). If you set no dates and no count, the actor returns filings from the last 30 days.

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

Only include filings filed on or before this date (YYYY-MM-DD). Leave empty for no upper bound.

## `maxFilingsPerTicker` (type: `integer`):

Stop after this many filings per ticker, newest first. Only applies when set; combine with dates to cap a window.

## `includeAmendments` (type: `boolean`):

Also process Form 4/A amendments. Amended rows carry form = 4/A so you can dedupe against the original.

## `includeDerivatives` (type: `boolean`):

Include Table II rows: options, RSUs, warrants and other derivative securities.

## `transactionCodes` (type: `array`):

Only keep these transaction codes. Leave empty for all. P = purchase, S = sale, A = grant, M = option exercise, F = tax withholding, G = gift, D = disposition to issuer.

## Actor input object example

```json
{
  "tickers": [
    "AAPL"
  ],
  "includeAmendments": false,
  "includeDerivatives": true
}
```

# Actor output Schema

## `insiderTransactions` (type: `string`):

One row per Form 4 transaction: insider, role, security, transaction code, shares, price, holdings after, 10b5-1 flag, and filing link.

## `errors` (type: `string`):

Inputs that could not be processed, with the reason. Present only when something failed; no row is charged for a failure.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("codecraftco/sec-insider-trades").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"] }

# Run the Actor and wait for it to finish
run = client.actor("codecraftco/sec-insider-trades").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"
  ]
}' |
apify call codecraftco/sec-insider-trades --silent --output-dataset

```

## MCP server setup

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

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/Vu5gnx3geNdlimr55/builds/hQmdxcf6mkb8hyeV0/openapi.json
