This repository is a compact, tested Python wrapper around the Equity Crowdfunding Leads Scraper on Apify. One command asks the Actor for campaigns from Wefunder, Republic and StartEngine and saves them locally as results.json and results.csv, already in a shared layout. For Wefunder campaigns that means founder, pitch line, region, target, amount raised, number of backers and pre-money valuation as a real number, which is exactly the shape a DataFrame wants. The collection runs on Apify's servers, so a notebook or a cron job on your laptop only waits for the run and reads the file.
Actor: Equity Crowdfunding Leads Scraper Β· Publisher: Devil Scrapes Β· Also in JavaScript: equity-crowdfunding-leads-scraper-javascript
- A single row layout for three portals: each campaign carries a
sourcevalue, so Wefunder, Republic and StartEngine records sit in the same table and you filter them with one column instead of three parsers. - Wefunder rows come loaded: the disclosed founder, the one-line pitch, region, goal, money raised so far, investor count, last-year revenue when published, and the pre-money valuation.
- Valuation as a number you can sort: shorthand such as
$62.1Mor$700Kis turned into a plain USD float, and a value that cannot be read becomesnullrather than a crash. - Honest coverage on the thinner sources: Republic and StartEngine rows give the slug, company name and campaign link; their money fields stay
nullbecause those sites render them in the browser. - Keyword narrowing: an optional case-insensitive substring is matched against each row's tagline or industry, and rows that match neither are left out before billing.
- A broken portal costs you one source, not the run: if a platform fails or stays blocked, it is logged and skipped while the remaining sources still deliver rows.
- Throttling handled for you: rate-limited or blocked pages are retried with growing pauses on a new proxy session before a source is given up.
Schedule python main.py on Monday mornings, read the CSV into pandas and sort the Wefunder rows by raised_amount_usd. The campaigns that are pulling money fastest float to the top, each one with a link back to its pitch page, and the whole review fits in one notebook cell.
Group the funded or raising rows by a keyword taken from tagline or industry, then compute the median valuation_usd per group. That gives founders and analysts a quick reference for what Reg CF companies in a given niche are asking, without copying numbers off campaign pages by hand.
Each run is a fresh snapshot, so keep every results.csv under a dated name and join consecutive files on source and campaign_slug. The change in raised_amount_usd and num_investors between two dates is a clean momentum metric for charts or a research note.
Explode the founders column so every name sits on its own row beside the company and campaign link, then import that sheet into your CRM. Teams selling to early-stage startups get companies that are visibly raising right now.
You need an Apify account and an API token from Console β Settings β Integrations. Apify's free plan includes monthly usage credit; this Actor's event prices are listed under Pricing below.
git clone https://github.com/devilscrapes/equity-crowdfunding-leads-scraper-python.git
cd equity-crowdfunding-leads-scraper-python
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export APIFY_TOKEN=your_token_here
python main.py # uses input.json
python main.py my-input.json --out data --max-charge 2The script starts the Equity Crowdfunding Leads Scraper, waits for it to finish, prints a link to the run in Apify Console and saves every result to results.json and results.csv. It exits with code 1 and the run's status message if the run fails.
Stripped down to the minimum, the integration is the snippet below. The apify-client package starts the run, blocks until it ends and then iterates the dataset page by page.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("DevilScrapes/equity-crowdfunding-leads").call(run_input={'sources': ['wefunder'], 'maxPerSource': 5, 'statusFilter': 'active', 'useProxy': True})
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item)main.py hands input.json to the Actor without changing it. The bundled example reads Wefunder only, keeps campaigns that are currently raising and stops after five rows, which is enough to see the full field set for a few cents. Leave sources empty to read all three portals, raise maxPerSource up to 500 per portal, or set industryFilter to a word like fintech.
{
"sources": [
"wefunder"
],
"maxPerSource": 5,
"statusFilter": "active",
"useProxy": true
}| Field | Type | Required | Default | Allowed values |
|---|---|---|---|---|
sources |
array | no | [] |
β |
maxPerSource |
integer | no | 50 |
β |
statusFilter |
string | no | "active" |
active, funded, all |
industryFilter |
string | no | β | β |
useProxy |
boolean | no | true |
β |
Each dataset row is one campaign. Money fields are plain floats in USD and num_investors is an integer, so pandas types them correctly on load; expect NaN in those columns for Republic and StartEngine rows, and for any Wefunder campaign that does not disclose a figure. founders is a list, which pandas keeps as a Python list per cell.
| Field | Type | Always present |
|---|---|---|
source |
string | yes |
campaign_slug |
string | yes |
company_name |
string | yes |
tagline |
string or null | no |
industry |
string or null | no |
location |
string or null | no |
founders |
array | yes |
website_url |
string or null | no |
target_amount_usd |
number or null | no |
raised_amount_usd |
number or null | no |
num_investors |
integer or null | no |
valuation_usd |
number or null | no |
revenue_usd |
number or null | no |
funding_stage |
string or null | no |
campaign_url |
string | yes |
scraped_at |
string | yes |
| Event | Price (USD) |
|---|---|
| Actor start | $0.2 |
| Campaign row | $0.005 |
Prices as configured on 2026-08-20. The Actor page always shows the current price. Runs are billed to the Apify account that owns the token. Use --max-charge to cap what a single run can cost.
This pandas sketch (pip install pandas) ranks the campaigns that disclose both money raised and valuation, adds two ratios, and writes a one-founder-per-row contact sheet next to it.
import json
import pandas as pd
rows = pd.DataFrame(json.load(open("results.json", encoding="utf-8")))
priced = rows.dropna(subset=["raised_amount_usd", "valuation_usd"]).copy()
backers = priced["num_investors"].where(priced["num_investors"] > 0)
priced["usd_per_investor"] = (priced["raised_amount_usd"] / backers).round(0)
priced["raised_share_of_valuation"] = (priced["raised_amount_usd"] / priced["valuation_usd"]).round(4)
ranked = priced.sort_values("raised_amount_usd", ascending=False)
print(ranked[["company_name", "raised_amount_usd", "num_investors", "usd_per_investor", "valuation_usd"]].head(15).to_string(index=False))
contacts = rows.explode("founders").dropna(subset=["founders"])
contacts = contacts.rename(columns={"founders": "founder"})
contacts[["founder", "company_name", "source", "location", "campaign_url"]].to_csv("founders.csv", index=False)
print(f"{len(contacts)} founder rows saved to founders.csv")No. The only credential is your Apify API token. None of the three portals asks you for a login, an investor profile or an API agreement to use this script.
Those two sites fill in raise totals, valuations and investor counts in the browser, so the Actor currently returns slug, company name and campaign URL for them. When you need numbers for analysis, set sources to ["wefunder"] and every row has the full field set the campaign discloses.
The cap is applied when campaigns are collected and the keyword filter runs afterwards, so a cap of 50 with industryFilter set to climate keeps only the matching part of those 50. Raise the cap if the filtered sample is too small; you are charged only for rows that pass.
Yes, on your side. The Actor stores no history between runs, and Apify's default storage on the free plan is removed after seven days. Save each CSV with its date, or append to a Parquet file, and compare snapshots on source plus campaign_slug.
Set APIFY_TOKEN first: export the token in the same shell, or put it in a local.envfile your shell loads. Never commit it.- Run finished with
FAILEDorABORTED: open the printed Console link; the run log says why. Input validation errors name the field. - Fewer rows than expected: a
--max-chargecap also limits how many results can be charged. Raise the cap or lower the limits in your input. - Something looks wrong in the data: open an issue on the Actor page so the maintainers see it.
- Equity Crowdfunding Leads Scraper on Apify Store
- JavaScript version of this example
- All Devil Scrapes Actors
- Apify web scraping cookbook
Related Actors:
- SEC EDGAR Filings Scraper β 10-K, 10-Q & 8-K β follow a crowdfunded issuer to its filings on SEC EDGAR.
- New Business Filings β US State Registry Leads Feed β freshly registered US companies from state registries, for an even earlier signal.
- OpenCorporates Alternative β US Business Registry Scraper β confirm a company's registration status and officers in US state registries.
MIT licensed example code. The Actor itself runs on Apify and is maintained by Devil Scrapes. Not affiliated with Wefunder, Republic or StartEngine.