Python tooling for authorized collection of Canadian securities filings from
SEDAR+, with legacy pre-2023 sedar.com code preserved
for reference.
SEDAR+ has no official public API. This project uses Playwright browser automation against the public UI, with compliance gates, rate limiting, and audit logging. Do not run live commands without written authorization — see docs/sedar-plus-and-data-access.md.
- Imports manual SEDAR+ CSV exports for documents or issuers without live browser automation.
- Searches current SEDAR+ profile, document, and reporting issuer screens when live access has been explicitly authorized.
- Stores issuer/profile metadata, filing metadata, sync audit records, and local downloaded files.
- Preserves legacy
sedar.comscraping code only for historical reference.
# Install package and Playwright browser
make setup
# Copy and edit configuration
cp .env.example .env
# Set SEDAR_AUTHORIZATION_FILE to your authorization document
# Verify configuration
sedar check-auth
# Live commands require explicit authorization
sedar sync-issuers --confirm-authorized
sedar search-profiles --query "Example Corp." --confirm-authorized
sedar search-docs --profile "Example Corp." --from-date 2024-01-01 --confirm-authorized
sedar download --limit 30 --confirm-authorized
# Import a manual CSV export (no live browser)
sedar import-csv exports/documents.csv --kind documents
sedar import-csv exports/issuers.csv --kind issuers| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL or SQLite connection | sqlite:///sedar.db |
SEDAR_AUTHORIZATION_FILE |
Path to authorization document | ./docs/authorization.example.txt |
SEDAR_CONFIRM_AUTHORIZED |
Opt-in for live automation (1/0) |
0 |
SEDAR_RATE_LIMIT_SECONDS |
Delay between browser actions | 4 |
SEDAR_DOWNLOAD_DIR |
Local filing storage | ./filings |
SEDAR_HEADLESS |
Headless browser (false for manual CAPTCHA) |
true |
SEDAR_BASE_URL |
SEDAR+ public website base URL | https://www.sedarplus.ca |
SEDAR_MAX_DOWNLOAD_BATCH |
Max documents per batch | 30 |
SEDAR_MAX_PROFILES_PER_SEARCH |
Max profiles per document search | 50 |
SEDAR_LOCALE |
SEDAR+ UI locale used in service links | en |
SEDAR_BROWSER_STATE_DIR |
Persisted Playwright browser state | .sedar/browser_state |
| Command | Description |
|---|---|
sedar check-auth |
Verify authorization file and database |
sedar sync-issuers |
Sync reporting issuers list |
sedar search-profiles |
Search SEDAR+ profiles and store metadata |
sedar search-docs |
Search documents and store metadata |
sedar download |
Download pending filings (max 30) |
sedar import-csv |
Import manual SEDAR+ CSV export |
sedar legacy-scrape |
Historical legacy scraper (deprecated) |
sedar sync-issuers [--max-pages N] --confirm-authorized
sedar search-profiles [--query TEXT] [--max-pages N] --confirm-authorized
sedar search-docs [--profile TEXT] [--query TEXT] [--from-date YYYY-MM-DD] [--to-date YYYY-MM-DD] [--max-pages N] --confirm-authorized
sedar download [--limit N] --confirm-authorized
sedar import-csv CSV_PATH --kind documents|issuers
Use sedar COMMAND --help for the exact option list installed in your environment.
Use this path when you do not have written permission for live automation, or when you want a reproducible import from files exported through the SEDAR+ UI.
sedar import-csv path/to/documents.csv --kind documents
sedar import-csv path/to/issuers.csv --kind issuersThe importer accepts common SEDAR+ CSV headers and normalizes them into the local
filing and company tables. Document links generated by SEDAR+ are preserved as
download_url when present.
Live commands call the public SEDAR+ browser UI and require both an authorization file and an explicit runtime confirmation.
sedar check-auth
sedar search-profiles --query "Example Corp." --max-pages 1 --confirm-authorized
sedar search-docs --profile "Example Corp." --query "Annual financial statements" --confirm-authorized
sedar download --limit 30 --confirm-authorizedsearch-docs supports --profile, --query, --from-date, --to-date, and
--max-pages. Date filters use YYYY-MM-DD.
sedar/
cli.py # CLI entry point
config.py # Settings
compliance.py # Authorization and rate limits
storage/ # PostgreSQL / SQLite via dataset
sedarplus/ # Playwright client (profiles, documents, issuers, downloads)
legacy/ # Pre-SEDAR+ scraper and CAPTCHA helper
docs/ # Data access guidance and authorization checklist
tests/ # Fixture-based unit tests
Metadata is stored in company, filing, and sync_run tables. Filings are saved
under SEDAR_DOWNLOAD_DIR/{profile_id}/{document_id}/.
The company table stores profile and issuer fields such as legal name, profile
number, jurisdiction, reporting jurisdictions, profile type, default status, and
active cease-trade-order status when available. The filing table stores document
metadata such as document ID, document name/type, submitted date, jurisdiction, file
size, company/profile name, generated URL, local path, and checksum.
Use PostgreSQL for production:
DATABASE_URL=postgresql://localhost/sedar
Use SQLite for local development:
DATABASE_URL=sqlite:///sedar.db
The tool writes local runtime state outside the source package:
sedar.dbwhen using the default SQLite database.filings/for downloaded documents..sedar/browser_state/state.jsonfor persisted Playwright browser state.- Browser downloads in temporary Playwright directories before files are saved into
SEDAR_DOWNLOAD_DIR.
Do not commit authorization documents, browser state, downloaded filings, or local databases unless your project policy explicitly allows it.
The original legacy sedar.com scraper lives in sedar/legacy/. Root scrape.py
and breaker.py are deprecation shims. Legacy endpoints were replaced by SEDAR+ in
July 2023 and are not maintained for current use.
- 30 documents per public download batch
- 50 profiles max per document search
- Public SEDAR+ exposes separate profile, document, reporting issuer, disciplined list, and cease trade order search services
- Public search results are browser UI output, not a documented public bulk API
- SEDAR+ maintenance pages and bot challenges are detected and surfaced as compliance errors
- Radware bot protection may require headed browser and manual CAPTCHA
- No official SEDAR+ API — UI automation may break when the site changes
| Symptom | Likely cause | Action |
|---|---|---|
Live SEDAR+ access requires explicit authorization |
--confirm-authorized was omitted and SEDAR_CONFIRM_AUTHORIZED is false |
Confirm written permission, then pass --confirm-authorized or set SEDAR_CONFIRM_AUTHORIZED=1 |
Authorization file not found |
SEDAR_AUTHORIZATION_FILE points to a missing file |
Set it to the written authorization document |
SEDAR+ is reporting scheduled maintenance |
The public site is unavailable | Retry after SEDAR+ maintenance ends |
SEDAR+ bot protection detected |
Radware or CAPTCHA blocked the browser session | Set SEDAR_HEADLESS=false, complete the browser challenge manually, then retry |
Requested N documents exceeds SEDAR+ batch limit |
--limit is above SEDAR_MAX_DOWNLOAD_BATCH |
Keep download batches at 30 or lower unless your authorization allows stricter configured behavior |
| Empty search import | CSV headers or UI table columns were not recognized | Keep the raw export and add a parser fixture before changing live automation |
make test # pytest
make lint # ruff check
make format # ruff formatCI runs lint and tests without live SEDAR+ access.
If the system Python is externally managed, use a local virtual environment:
python3 -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/python -m pytest -qThis tool is for authorized research and operational use only. Review the current SEDAR+ Terms of Use before collecting, storing, or redistributing filing data. This repository is not legal advice.