Action
Append to Logseq
UPDATES
about 23 hours ago
Updated formatting of the Readme
about 23 hours ago
Updated formatting of the Readme
about 23 hours ago
Updated the documentation to make it clear that this is for Logseq DB.
1 day ago
Updated to strip existing some formatting (as described) before import.
Send to Logseq Journal - Drafts Action
Appends draft content to today’s journal page in Logseq. The first line becomes the parent block, and remaining lines become nested children.
Prerequisites
Logseq version 2.x.x (The DB version of Logseq.)
Logseq HTTP API Server must be enabled:
- Open Logseq → Settings → Features
- Enable “HTTP APIs server”
- Note your API token (or set one)
Logseq must be running when you use the action
Setting Up the Action in Drafts
Step 1: Create New Action
- Open Drafts
- Go to Actions list
- Tap + to create a new action
- Configure:
- Name: Send to Logseq Journal
- Icon: Choose an icon (e.g.,
arrow.up.doc) - Color: Choose a color
Step 2: Add Script Step
- Tap Steps
- Tap + → Advanced → Script
- Enable “Allow asynchronous execution” (critical!)
- Paste the contents of
send-to-logseq-journal.js
Step 3: Configure After Success
- Go to action settings
- Under After Success:
- Add Tag:
sent-to-logseq - Archive: Enable
- Add Tag:
Step 4: First Run - API Token
On first run, Drafts will prompt for your Logseq API token:
- Get your token from Logseq → Settings → Features → HTTP APIs server
- Enter the token when prompted
- The token is stored securely in Drafts’ credential system
Usage
- Write your content in a draft
- First line = parent block
- Additional lines = child blocks (nested under parent)
- Run the action
- Content appears in today’s Logseq journal
Example
Draft content:
## Meeting notes from project sync
- Discussed timeline for Q1
- Action items assigned to team
- Follow-up scheduled for Friday
Result in Logseq journal:
- Meeting notes from project sync
- Discussed timeline for Q1
- Action items assigned to team
- Follow-up scheduled for Friday
Content cleanup:
- Header marks (
#,##, etc.) are stripped from the first line - Bullet prefixes (
-,*,+) are stripped from child lines - Numbered lists (
1.,2., etc.) are preserved as-is
Troubleshooting
“HTTP request failed”
- Ensure Logseq is running
- Verify HTTP API server is enabled in Logseq settings
- Check that port 12315 is not blocked
“Failed to append block”
- Verify your API token is correct
- Try resetting credentials: long-press action → Manage Credentials → Forget
Wrong journal date format
The script uses Logseq’s default format: “Jan 17th, 2026”
If your Logseq uses a different journal format, edit the formatLogseqJournalDate() function in the script.
Resetting Credentials
To change your API token:
- Long-press the action
- Select Manage Credentials
- Tap Forget on “Logseq API”
- Run the action again to enter new token
Steps
-
script
// Send to Logseq Journal - Drafts Action Script // Version: 1.2.0 // // This script appends draft content to today's journal in Logseq. // First line becomes the parent block, remaining lines become children. // // Requirements: // - Logseq running with HTTP API server enabled // - API token configured in Logseq settings // - "Allow asynchronous execution" enabled in Drafts action step // ============================================ // Configuration // ============================================ const LOGSEQ_API_URL = "http://127.0.0.1:12315/api"; // ============================================ // Helper Functions // ============================================ /** * Strip markdown header marks from text (e.g., "## Title" -> "Title") */ function stripHeaderMarks(text) { return text.replace(/^#+\s*/, ""); } /** * Strip list marker prefixes from text (e.g., "- item" -> "item") * Handles: -, *, + (but NOT numbered lists, which are preserved) */ function stripListPrefix(text) { // Strip leading whitespace, then bullet prefix (-, *, +) followed by space return text.replace(/^\s*[\-\*\+]\s+/, ""); } /** * Format date for Logseq journal page name * Logseq default format: "Jan 17th, 2026" */ function formatLogseqJournalDate(date) { const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const day = date.getDate(); const suffix = (day === 1 || day === 21 || day === 31) ? "st" : (day === 2 || day === 22) ? "nd" : (day === 3 || day === 23) ? "rd" : "th"; return months[date.getMonth()] + " " + day + suffix + ", " + date.getFullYear(); } /** * Make a request to Logseq HTTP API */ function logseqRequest(method, args, token) { var http = HTTP.create(); var response = http.request({ "url": LOGSEQ_API_URL, "method": "POST", "encoding": "json", "headers": { "Authorization": "Bearer " + token, "Content-Type": "application/json" }, "data": { "method": method, "args": args } }); return response; } /** * Parse response from Logseq API */ function parseResponse(response) { if (!response.success) { return { success: false, error: "HTTP request failed with status " + response.statusCode }; } try { var data = JSON.parse(response.responseText); if (data.error) { return { success: false, error: data.error.message || JSON.stringify(data.error) }; } return { success: true, result: data }; } catch (e) { return { success: false, error: "Failed to parse response: " + e.message }; } } // ============================================ // Main Script // ============================================ // 1. Get API token from secure credential storage var credential = Credential.create("Logseq API", "Logseq HTTP API authentication token"); credential.addPasswordField("token", "API Token"); if (!credential.authorize()) { app.displayErrorMessage("Authorization cancelled"); context.fail(); script.complete(); } var token = credential.getValue("token"); if (!token || token.trim() === "") { app.displayErrorMessage("No API token provided"); context.fail(); script.complete(); } // 2. Get graph name from configured value (optional - not used in API calls but documented) // var graphName = context.configuredValues["graphName"]; // 3. Parse draft content var lines = draft.content.split("\n").filter(function(line) { return line.trim() !== ""; }); if (lines.length === 0) { app.displayErrorMessage("Draft is empty"); context.fail(); script.complete(); } var parentContent = stripHeaderMarks(lines[0]); var childLines = lines.slice(1).map(function(line) { return stripListPrefix(line); }); // 4. Get today's journal page name var today = new Date(); var journalPage = formatLogseqJournalDate(today); // 5. Append parent block to journal page app.displayInfoMessage("Sending to Logseq..."); var appendResponse = logseqRequest( "logseq.Editor.appendBlockInPage", [journalPage, parentContent], token ); var appendResult = parseResponse(appendResponse); if (!appendResult.success) { app.displayErrorMessage("Failed to append block: " + appendResult.error); context.fail(); script.complete(); } // 6. Get parent block UUID and insert children var parentBlock = appendResult.result; if (childLines.length > 0 && parentBlock && parentBlock.uuid) { var parentUUID = parentBlock.uuid; var failedChildren = []; for (var i = 0; i < childLines.length; i++) { var childContent = childLines[i]; // Insert child block under parent var childResponse = logseqRequest( "logseq.Editor.insertBlock", [parentUUID, childContent, {"sibling": false}], token ); var childResult = parseResponse(childResponse); if (!childResult.success) { failedChildren.push(i + 2); // Line number (1-indexed, +1 for parent) } else if (childResult.result && childResult.result.uuid) { // Update parentUUID to the last inserted child for sequential insertion // Actually, we want all children under the original parent, so don't update // parentUUID = childResult.result.uuid; } } if (failedChildren.length > 0) { app.displayWarningMessage("Some children failed (lines: " + failedChildren.join(", ") + ")"); } } // 7. Success! var childCount = childLines.length; var message = "Sent to " + journalPage; if (childCount > 0) { message += " (" + childCount + " child block" + (childCount > 1 ? "s" : "") + ")"; } app.displaySuccessMessage(message); // Signal async completion script.complete();
Options
-
After Success Archive , Tags: sent-to-logseq Notification Info Log Level Info