A reliability-first automation framework for publishing content to Substack using controlled browser workflows, session integrity, and human-in-the-loop checkpoints. This project is designed to diagnose and stabilize posting pipelines where naive automation attempts fail during submission. The focus is not shortcuts, but building a resilient publishing system that mirrors real editorial workflows while remaining observable and configurable.
Created by Appilot, built to showcase our approach to Automation!
If you are looking for custom Substack Browser Posting Automation Framework , you've just found your team — Let’s Chat.👆 👆
Posting to Substack programmatically can fail even when login succeeds. In practice, issues often appear at submission time due to session state, editor lifecycle, draft validation, or timing mismatches between UI and backend expectations.
This framework reframes the problem from “script clicks publish” to a stateful publishing pipeline: drafts are prepared, editor readiness is verified, submission is validated, and outcomes are confirmed—step by step.
- Treats Substack posting as a stateful workflow, not a single action
- Separates draft creation, editor hydration, and publish confirmation
- Adds observability to pinpoint where posting fails
- Uses conservative timing and validation to reduce submission errors
- Keeps humans in control at critical checkpoints
| Feature | Description |
|---|---|
| Stateful Editor Handling | Waits for editor initialization and content hydration before actions |
| Draft-First Workflow | Creates and validates drafts prior to any publish attempt |
| Session Integrity Checks | Verifies cookies, storage, and auth state before posting |
| Editor Readiness Validation | Confirms required UI and data states are present |
| Human Review Gate | Optional pause for manual confirmation before publish |
| Controlled Submission Flow | Executes publish only after all validations pass |
| Outcome Verification | Confirms post visibility after submission |
| Error Classification | Categorizes failures by editor, session, or network stage |
| Retry with Guardrails | Retries only safe, idempotent steps |
| Evidence Capture | Screenshots and DOM snapshots on failure |
| Detailed Logging | Step-level logs for diagnosing where automation breaks |
| Config-Driven Timing | Centralized control over waits and thresholds |
| Step | Description |
|---|---|
| Input or Trigger | A new article draft and metadata are queued for publishing |
| Core Logic | The system opens Substack, restores session, loads editor, injects content, and validates state |
| Publish Attempt | Submission occurs only after editor and draft checks succeed |
| Output or Action | Post is published or safely halted with diagnostic artifacts |
| Safety Controls | Conservative timing, validation gates, and manual checkpoints |
| Component | Description |
|---|---|
| Language | Python |
| Frameworks | Playwright |
| Tools | Chromium |
| Infrastructure | Docker, GitHub Actions |
substack-browser-posting-automation-framework/
├── src/
│ ├── main.py
│ ├── runner.py
│ ├── session/
│ │ ├── session_loader.py
│ │ ├── auth_validator.py
│ │ └── storage_guard.py
│ ├── editor/
│ │ ├── editor_loader.py
│ │ ├── readiness_checks.py
│ │ └── content_injector.py
│ ├── publishing/
│ │ ├── draft_creator.py
│ │ ├── publish_flow.py
│ │ └── confirmation_checker.py
│ ├── diagnostics/
│ │ ├── error_classifier.py
│ │ ├── dom_snapshot.py
│ │ └── screenshot.py
│ └── utils/
│ ├── logger.py
│ ├── timing.py
│ └── config_loader.py
├── config/
│ ├── editor.yaml
│ ├── timing.yaml
│ └── workflow.yaml
├── logs/
│ ├── runs/
│ └── posting.log
├── output/
│ ├── drafts.json
│ └── publish_results.json
├── tests/
│ ├── test_editor_checks.py
│ └── test_publish_flow.py
├── requirements.txt
└── README.md
- Newsletter operators use it to publish consistently without manual retries.
- Automation engineers use it to diagnose why posting fails at submission time.
- Content teams use it to standardize draft-to-publish workflows.
- Experimenters use it to compare browser flows and editor states safely.
Why does login succeed but publishing fails?
Because publishing depends on editor state, draft hydration, and validation steps beyond authentication. Missing or premature actions can invalidate submission.
Does this rely on API endpoints?
No. It uses browser workflows to align with how the editor actually behaves, reducing mismatches between UI and backend expectations.
Can I pause before publishing to review content?
Yes. A human approval gate can be enabled to stop the workflow before submission.
How do I debug failures effectively?
Each failure produces logs, screenshots, and DOM snapshots so you can see exactly which state was missing or invalid.
Execution Speed:
Draft preparation and validation complete in 30–90 seconds depending on editor load time
Success Rate:
90–94% successful publishes in stable conditions with validation gates enabled
Scalability:
Supports multiple newsletters via isolated sessions and parallel runners
Resource Efficiency:
~400–700 MB RAM per active browser session during editor interaction
Error Handling:
Step-level validation, guarded retries, evidence capture, and safe halting before irreversible actions
