Publishing to Medium Without APIs Using Chrome Extensions
Learn how to build a zero-API publishing extension for platforms with deprecated write APIs by leveraging active browser sessions and contenteditable DOM injection.
Table of Contents7 sections

When publishing platforms deprecate their developer APIs, automated syndication pipelines break. Technical bloggers and content engineers writing in local Markdown editors or static site generators are forced to manually copy and paste articles, re-format code blocks, re-upload inline graphics, and re-enter canonical URLs. Existing automation workarounds often rely on headless browser runners like Puppeteer or Playwright operating inside continuous integration servers. These headless runners require storing plaintext user credentials or session cookies on remote machines, which frequently trigger bot detection mechanisms or two factor authentication challenges. For a related implementation, see Automated Content Syndication Canonical Seo Protection.
Quick Workflow: Session-Native Medium Publishing Extension
- In-Session Execution: Manifest V3 extension runs within the user’s active authenticated browser tab, bypassing remote bot challenges and login CAPTCHAs.
- Rich Text Framework Compatibility: Interacts with Slate/ProseMirror contenteditable models using synthetic clipboard events (
insertHTML) rather than raw innerHTML mutation.- Canonical Link Automation: Programmatically sets original publication URLs in publishing settings to guarantee search attribution and prevent content penalties.
- Zero Server Credentials: No passwords, API secrets, or cookies leave the client workstation.
This article examines an alternative architectural pattern that bypasses server-side bot detection entirely. By building a Manifest V3 Chrome extension that operates directly inside the user’s authentic, already-authenticated browser session, developers can programmatically transfer formatted content into modern web editors without maintaining remote servers or storing private credentials.
The Session-Native Alternative
Traditional server-driven automation treats the web as an API endpoint, attempting to simulate user actions from headless contexts. Platforms counter these headless instances with advanced fingerprinting, IP reputation scoring, and behavior analysis. When an automation script attempts to log in programmatically, it often encounters account lockouts or CAPTCHA challenges.
An extension-based approach inverts this model. The user is already logged into their publishing platform within their everyday browser. The extension injects scripts directly into the active tab where a valid session already exists. Because the request originates from the legitimate browser instance with active cookies and local storage intact, the platform perceives the action as standard user behavior. This eliminates the need for headless runners, password storage, and remote infrastructure while keeping execution entirely client-side.
The ContentEditable Challenge
Injecting content into modern web applications presents technical hurdles because platforms like Medium rely on rich text frameworks such as Draft.js, Slate, or ProseMirror. These frameworks maintain an internal JavaScript state model that governs the DOM, rather than treating the DOM as the source of truth. For a related implementation, see Automating Medium Draft Workflows.
If an extension attempts to update the editor by directly modifying .innerHTML or setting element.textContent, the underlying framework remains unaware of the change. The user interface may appear updated briefly, but the moment the user types a character or clicks save, the framework flushes its internal model over the modified DOM, erasing the injected text. Furthermore, direct mutations bypass the editor transaction history, breaking undo and redo stacks.
Synthetic Events and Clipboard Injection
To update stateful rich text editors reliably, automation scripts must interact with the browser event lifecycle in a manner that simulates genuine user input. Modern editors listen for input events and clipboard transactions to update their internal model.
Below is an implementation pattern demonstrating how to locate the target editor container and dispatch a synthetic input transaction using execCommand combined with proper event dispatching.
async function injectContentToEditor(htmlContent) {
const editorSelector = '[contenteditable="true"]';
const editor = document.querySelector(editorSelector);
if (!editor) {
throw new Error('Target contenteditable container not found');
}
editor.focus();
// Create a selection inside the editor
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(editor);
selection.removeAllRanges();
selection.addRange(range);
// Execute native insert command to preserve editor state model
const success = document.execCommand('insertHTML', false, htmlContent);
if (!success) {
// Fallback to synthetic input event dispatch
const dataTransfer = new DataTransfer();
dataTransfer.setData('text/html', htmlContent);
const inputEvent = new InputEvent('beforeinput', {
bubbles: true,
cancelable: true,
inputType: 'insertFromPaste',
dataTransfer: dataTransfer
});
editor.dispatchEvent(inputEvent);
}
}
This approach forces the framework to process the inserted HTML through its standard sanitization and model-update pipelines, preserving formatting for code blocks, lists, and inline styles.
Preserving Canonical Attribution
Syndicating content from a primary personal blog or documentation site to external publishing platforms introduces duplicate content risks for search engine optimization. Search engines require a clear signal indicating which URL represents the original source of truth.
An automated publishing extension should handle canonical attribution programmatically. During the payload transformation phase, the extension extracts the canonical URL of the source article and injects the corresponding metadata or footer attribution before finalizing the draft state. While platforms handle canonical links through their internal settings menus rather than direct DOM tag injection, automating the insertion of source attribution text at the end of the document body protects original domain authority and ensures readers can trace back to the primary publication.
Privacy by Design
Client-side extension architectures remove privacy liabilities common in cloud-based publishing tools. Because all article parsing, Markdown transformation, and DOM injection happen locally inside the browser, no article content or session identifiers ever traverse a third-party server. Developers maintain absolute ownership of their publishing workflow without relying on paid middleware, external databases, or analytics trackers.
Conclusion
When platform maintainers deprecate developer APIs, developers can maintain automated publishing workflows by shifting execution to the client layer. By combining Manifest V3 extensions, active browser sessions, and event-aware DOM injection, it is possible to transfer structured content into stateful editors securely and reliably without resorting to fragile headless servers or storing plaintext credentials.
Continue Exploring
You Might Also Like

breadcrumblist JSON-LD Synchronization and Maintenance
Learn how to keep visible breadcrumb trails and JSON-LD structured data synchronized by generating both from a single source of truth.

Gemini API Backup Key 503 Bounded Failover
Learn how to build a bounded failover chain for Gemini API keys that handles both quota exhaustion and transient server errors without leaking secrets.

Knowledge Base Bot Abstain: No Supporting Article Retrieval
Learn how to build a knowledge base bot that safely abstains when its local index lacks matching answers, distinguishing related passages from true evidence.