Automating TikTok Slideshow Content Creation: A Zero-Cost, Scalable Workflow from Hook Research to Scheduled Publishing
“
Core question: How can creators build a repeatable, low-cost pipeline for producing TikTok slideshow content without relying on expensive design tools or AI-generated imagery?
The answer is straightforward: extract proven hooks from viral TikTok content, source free high-quality images from Pinterest, generate slides programmatically using Node.js, and schedule distribution through an open-source CLI tool. Once configured, this workflow enables batch production of 30 posts per week in approximately two hours, with near-zero operational costs.
Why This Workflow Works
“
Summary: Manual content creation is time-consuming and inconsistent. This workflow replaces expensive SaaS tools with open-source alternatives and replaces guesswork with data-driven hook extraction.
Most creators today still follow a fully manual process: brainstorm an idea, design individual slides in a visual editor, and post one by one. This approach consumes hours per piece and produces uneven results. The workflow described here addresses three fundamental pain points:
| Pain Point | Traditional Approach | This Automated Workflow |
|---|---|---|
| Tooling cost | Canva Pro + Buffer/Later/Hootsuite subscriptions, $10–50/month | Near-zero cost; self-hosted Postiz has no publishing limits |
| Production scale | 1–2 posts per day, difficult to batch | 30 posts per week in ~2 hours |
| Content quality | Hooks written from intuition, low hit rate | Hooks extracted from proven viral videos, higher probability of engagement |
Author reflection: Early in my own experimentation, I tried using Midjourney to generate slide backgrounds. The costs accumulated quickly, and I noticed something counterintuitive: AI-generated “perfect” images often lacked the relatable quality of real photographs. A genuine coffee cup on a cluttered desk, morning light through real curtains—these authentic visuals from Pinterest consistently outperformed polished AI renders in stopping the scroll.
The Five-Stage Pipeline at a Glance
“
Summary: The workflow moves from research to execution in five connected stages, each with defined inputs and outputs.
[TikTok Scroll & Research] → [SnapTik Download] → [Claude Opus Hook Extraction]
↓
[Pinterest Image Sourcing] → [Node.js Canvas Script → PNG Slides]
↓
[Postiz Agent CLI → Scheduled Draft]
↓
[TikTok App → Drafts → Manual Publish at Peak Time]
This pipeline transforms content creation from a craft project into a repeatable manufacturing process. Each stage feeds directly into the next, eliminating the friction of starting from a blank canvas every time.
Stage 1: Finding Proven Hooks on TikTok
“
Core question: Where can you find opening lines and visual patterns that are already proven to stop the scroll?
The hook—the first three seconds of content—determines whether a viewer stops scrolling or swipes away. Rather than inventing hooks from scratch, the most reliable method is to study content that TikTok’s algorithm has already validated as engaging.
How to Scroll with Purpose
Open TikTok and search for keywords specific to your niche. Different verticals cluster around recognizable “Tok” tags:
-
Education: StudyTok, BookTok -
Fitness: GymTok, FitTok -
Finance: MoneyTok, FinanceTok
Filter results by “Most Liked” or “Most Recent” to surface currently trending content. While watching, train yourself to notice three specific elements:
-
The first text overlay, appearing within the first two seconds -
The opening line, typically framed as a question or shocking statement -
Recurring structural patterns, such as: -
“You’re doing X wrong” -
“X things Y never tells you” -
“I did X and here’s what happened”
-
Downloading Videos for Analysis
Use SnapTik or SSSTik to download videos without watermarks for closer study:
-
Copy the TikTok video link -
Visit SnapTik.app or sss.tiktok.ws -
Paste the link and select “Download Without Watermark”
Save these files locally. They will be uploaded to Claude Opus in the next stage for structural analysis.
Author reflection: The first time I did this exercise, I downloaded twenty videos from StudyTok and realized that fourteen of them used nearly identical hook structures. The algorithm was telling me exactly what worked, but I had been ignoring the data because I was too focused on “being original.” Originality, I learned, is better applied to execution than to reinventing structures that are already working.
Stage 2: Extracting and Generating Hooks with Claude Opus
“
Core question: How do you systematically deconstruct a viral video’s opening and generate new, testable variations?
This is the step most creators skip. Instead of guessing what might work, Claude Opus analyzes the patterns in viral slideshows and generates new hooks based on proven structural templates.
Prompt for Hook Extraction from Slideshow Images
Upload the slideshow images (or a PDF/carousel export) to Claude Opus, then use the following prompt:
Analyze this TikTok slideshow and:
1. Identify the main hook used in the first slide (focus on text overlay, headline, and visual framing)
2. Explain why this hook works (curiosity / pain point / surprise / relatability)
3. Break down the hook structure (e.g., number + outcome, negative framing, identity targeting)
4. Write 5 similar hook variations for the [YOUR NICHE HERE] niche
- Each hook under 10 words
- Format: a question OR a strong statement
- Avoid generic openers like "Did you know"
Output as a numbered list, one hook per line.
Prompt for Text-Only Hook Extraction
If you have manually transcribed the slide content:
Here is the content of a viral TikTok slideshow in the [NICHE] niche:
[PASTE CONTENT HERE]
Task:
- Identify the core hook from the first slide
- Write 7 hook variations for a similar slideshow
- Each hook must trigger one of 3 emotions: curiosity / FOMO / empathy
- Max 8 words per hook
- Include a short explanation of why each hook works
Real Output Example
For the personal finance niche, Claude might return:
-
“I saved $5k in 6 months” — Number + specific outcome, triggers curiosity -
“You’re saving money wrong” — Negative framing, challenges existing behavior -
“The money trap nobody warns you about” — Information gap, triggers FOMO -
“Stop putting money in these 3 things” — List format + negative action, high specificity -
“Why your paycheck disappears every month” — Direct pain point, high relatability
Building Your Hook Library
Save all extracted and generated hooks into a structured repository:
-
Obsidian (recommended for its bi-directional linking and graph view) -
Notion (ideal for team collaboration) -
Google Sheets (simplest and most accessible)
Over time, this library becomes a compounding asset. Future content creation becomes faster because you are selecting from a validated pool rather than inventing from nothing.
Bonus: Extracting Visual Style and Pinterest Search Terms
“
Core question: How do you ensure the images you find match the emotional tone of your hooks, rather than choosing visuals at random?
While the slideshow is still loaded in Claude Opus, run an additional analysis to generate precise search terms for the image sourcing stage.
Visual Analysis Prompt
Now look at the visual style of this slideshow:
1. Describe the color palette, lighting, and overall aesthetic (dark/moody, bright/clean, luxury, minimal, etc.)
2. What kind of images would work as slideshow backgrounds for the hooks you just wrote?
3. Give me 5 specific Pinterest search queries to find those images
- Format: short keyword phrases, 2–4 words each
- Optimized for Pinterest search, not Google
Example Output for Personal Finance
-
dark aesthetic desk -
minimal finance flatlay -
coffee workspace moody -
money saving aesthetic -
clean office setup
Copy these directly into Pinterest search. This precision eliminates the guesswork of broad keyword searches and returns visually consistent results.
Stage 3: Sourcing Images from Pinterest
“
Core question: Where can you find free, high-quality, portrait-oriented images that fit TikTok’s vertical format?
Pinterest functions as an effectively unlimited free image library. Compared to AI-generated visuals, real photography on Pinterest often generates stronger audience resonance—and costs nothing.
Criteria for Effective TikTok Images
| Attribute | Recommendation | Rationale |
|---|---|---|
| Aspect ratio | Prioritize portrait / 9:16 | Native vertical experience on TikTok |
| Color palette | Bold, high contrast | The TikTok feed is visually competitive; soft pastels get lost |
| Text content | Minimal existing text | You will overlay your own typography |
| Emotional tone | Match the hook’s energy | Finance hooks pair with lifestyle imagery; fitness hooks with action shots |
Using Claude-Generated Search Terms
Paste the five Pinterest search queries from the previous stage directly into the search bar. Each query targets a specific visual mood rather than a broad topic, producing more consistent and on-brand results.
Three Methods for Downloading Pinterest Images
Method 1: PinDown Chrome Extension (Recommended)
-
Install the PinDown extension in Chrome -
Open a Pinterest image → Click the PinDown icon → Download full resolution
Method 2: Direct Right-Click
-
Click the image to open full size -
Right-click → “Open image in new tab” -
Right-click the image → “Save image as”
Method 3: Python Bulk Downloader (For Full Automation)
# pinterest_downloader.py
import requests
from pathlib import Path
def download_image(url: str, filename: str, folder: str = "pinterest_images"):
Path(folder).mkdir(exist_ok=True)
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(f"{folder}/{filename}.jpg", "wb") as f:
for chunk in response.iter_content(1024):
f.write(chunk)
print(f"Downloaded: {filename}")
# Paste direct image URLs from Pinterest
urls = [
"https://i.pinimg.com/originals/...", # URL 1
"https://i.pinimg.com/originals/...", # URL 2
]
for i, url in enumerate(urls):
download_image(url, f"image_{i+1:03d}")
Organize by Niche
pinterest_images/
├── finance/
├── fitness/
└── lifestyle/
This folder structure enables rapid asset retrieval when switching between content verticals.
Stage 4: Generating Slides with Node.js Canvas
“
Core question: How do you programmatically overlay text on images and export publication-ready PNG files without opening a design tool?
Using a Node.js script, you can batch-generate 1080×1920 PNG slides by overlaying hook text onto Pinterest images. This eliminates manual design work and ensures consistent output dimensions.
Standard Slideshow Structure
A typical six-slide TikTok slideshow follows this narrative arc:
| Slide | Content | Purpose |
|---|---|---|
| 1 | Hook | Stop the scroll in the first second |
| 2 | Problem / Setup | Build relatability—”this is about you” |
| 3 | Point 1 | First actionable insight |
| 4 | Point 2 | Second actionable insight |
| 5 | Point 3 | Third actionable insight |
| 6 | CTA | Follow, save, comment, or download prompt |
Environment Setup
mkdir tiktok-slide-gen && cd tiktok-slide-gen
npm init -y
npm install canvas @napi-rs/canvas sharp
@napi-rs/canvas is a fast, native Node.js canvas implementation that does not require a browser environment.
Core Generation Script
// generate-slides.js
import { createCanvas, loadImage, GlobalFonts } from '@napi-rs/canvas'
import { writeFileSync, mkdirSync } from 'fs'
import { join } from 'path'
// ─── CONFIG ───────────────────────────────────────────────
const OUTPUT_DIR = './output'
const CANVAS_W = 1080
const CANVAS_H = 1920
const OVERLAY_OPACITY = 0.52 // Dark overlay on image, 0–1
const OVERLAY_COLOR = '0,0,0' // RGB for overlay
// Optional: load a custom font (TTF/OTF)
// GlobalFonts.registerFromPath('./fonts/Inter-Bold.ttf', 'InterBold')
// ─── SLIDE DEFINITIONS ────────────────────────────────────
// Each slide: { imagePath, lines: [{ text, size, weight, y }] }
const slides = [
{
imagePath: './pinterest_images/finance/image_001.jpg',
lines: [
{ text: 'I saved $5k in 6 months', size: 88, weight: 'bold', y: 860 },
{ text: 'doing this one thing', size: 72, weight: 'normal', y: 970 },
],
},
{
imagePath: './pinterest_images/finance/image_002.jpg',
lines: [
{ text: 'Most people spend', size: 64, weight: 'normal', y: 820 },
{ text: 'before they save.', size: 64, weight: 'bold', y: 910 },
{ text: "Here's why that's a trap.", size: 56, weight: 'normal', y: 990 },
],
},
{
imagePath: './pinterest_images/finance/image_003.jpg',
lines: [
{ text: '01. Pay yourself first', size: 72, weight: 'bold', y: 900 },
{ text: 'Move 20% to savings on payday.', size: 52, weight: 'normal', y: 990 },
{ text: 'Before any expense hits.', size: 52, weight: 'normal', y: 1060 },
],
},
{
imagePath: './pinterest_images/finance/image_004.jpg',
lines: [
{ text: '02. Kill subscriptions', size: 72, weight: 'bold', y: 900 },
{ text: 'Audit every recurring charge.', size: 52, weight: 'normal', y: 990 },
{ text: 'Cancel what you forgot existed.', size: 52, weight: 'normal', y: 1060 },
],
},
{
imagePath: './pinterest_images/finance/image_005.jpg',
lines: [
{ text: '03. Use cash envelopes', size: 72, weight: 'bold', y: 900 },
{ text: 'Allocate per category, in cash.', size: 52, weight: 'normal', y: 990 },
{ text: 'When it runs out, it runs out.', size: 52, weight: 'normal', y: 1060 },
],
},
{
imagePath: './pinterest_images/finance/image_006.jpg',
lines: [
{ text: 'Save this post 🔖', size: 80, weight: 'bold', y: 860 },
{ text: 'Follow for more money tips', size: 56, weight: 'normal', y: 970 },
{ text: 'every week →', size: 56, weight: 'normal', y: 1050 },
],
},
]
// ─── HELPERS ──────────────────────────────────────────────
function wrapText(ctx, text, maxWidth) {
const words = text.split(' ')
const lines = []
let current = ''
for (const word of words) {
const test = current ? `${current} ${word}` : word
if (ctx.measureText(test).width > maxWidth && current) {
lines.push(current)
current = word
} else {
current = test
}
}
if (current) lines.push(current)
return lines
}
async function generateSlide(slide, index) {
const canvas = createCanvas(CANVAS_W, CANVAS_H)
const ctx = canvas.getContext('2d')
// 1. Draw background image, cover-fit
const img = await loadImage(slide.imagePath)
const scale = Math.max(CANVAS_W / img.width, CANVAS_H / img.height)
const drawW = img.width * scale
const drawH = img.height * scale
const offsetX = (CANVAS_W - drawW) / 2
const offsetY = (CANVAS_H - drawH) / 2
ctx.drawImage(img, offsetX, offsetY, drawW, drawH)
// 2. Dark overlay
ctx.fillStyle = `rgba(${OVERLAY_COLOR},${OVERLAY_OPACITY})`
ctx.fillRect(0, 0, CANVAS_W, CANVAS_H)
// 3. Draw each line of text
const PADDING = 80
const MAX_TEXT_W = CANVAS_W - PADDING * 2
for (const line of slide.lines) {
ctx.font = `${line.weight} ${line.size}px sans-serif`
ctx.fillStyle = '#ffffff'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
// Drop shadow
ctx.shadowColor = 'rgba(0,0,0,0.75)'
ctx.shadowBlur = 12
ctx.shadowOffsetY = 4
const wrapped = wrapText(ctx, line.text, MAX_TEXT_W)
const lineHeight = line.size * 1.2
wrapped.forEach((l, i) => {
ctx.fillText(l, CANVAS_W / 2, line.y + i * lineHeight)
})
}
// 4. Export PNG
mkdirSync(OUTPUT_DIR, { recursive: true })
const outPath = join(OUTPUT_DIR, `slide_${String(index + 1).padStart(2, '0')}.png`)
const buffer = canvas.toBuffer('image/png')
writeFileSync(outPath, buffer)
console.log(`✓ ${outPath}`)
}
// ─── MAIN ─────────────────────────────────────────────────
async function main() {
console.log(`Generating ${slides.length} slides...`)
for (let i = 0; i < slides.length; i++) {
await generateSlide(slides[i], i)
}
console.log(`\nDone → ${OUTPUT_DIR}/`)
}
main().catch(console.error)
Running the Script
node generate-slides.js
Expected output:
Generating 6 slides...
✓ output/slide_01.png
✓ output/slide_02.png
✓ output/slide_03.png
✓ output/slide_04.png
✓ output/slide_05.png
✓ output/slide_06.png
Done → output/
Using Custom Fonts
Download any TTF/OTF font (e.g., Inter Bold, Montserrat Black) and register it:
import { GlobalFonts } from '@napi-rs/canvas'
GlobalFonts.registerFromPath('./fonts/Montserrat-Black.ttf', 'MontserratBlack')
// Then use in ctx.font:
ctx.font = `bold 88px MontserratBlack`
Batch Generation from JSON Config
Instead of editing the script for each campaign, drive generation from a JSON file:
// slides-config.json
[
{
"imagePath": "./pinterest_images/finance/image_001.jpg",
"lines": [
{ "text": "I saved $5k in 6 months", "size": 88, "weight": "bold", "y": 860 },
{ "text": "doing this one thing", "size": 72, "weight": "normal","y": 970 }
]
}
]
Replace the slides array in generate-slides.js with:
import { readFileSync } from 'fs'
const slides = JSON.parse(readFileSync('./slides-config.json', 'utf-8'))
Now content teams can edit slides-config.json without touching code. Combined with the hook list from Claude Opus output, this creates a fully automated content pipeline.
Author reflection: The first time I ran this script, six slides rendered in under three seconds. The realization was immediate: the bottleneck in content creation was never “how fast can I make an image.” It was “how fast can I make a decision”—about the hook, the image, the structure. The script simply executes decisions that have already been made. The real work is upstream.
Stage 5: Installing and Configuring Postiz Agent CLI
“
Core question: How do you automate the upload and scheduling of generated slides to TikTok without manual intervention?
Postiz serves as your distribution command center, handling timing, cross-posting, and engagement automation. The self-hosted version has no publishing limits, unlike the restricted free tiers of commercial alternatives.
Installation and Authentication
# Install globally
npm install -g postiz
# Set API key (add to ~/.zshrc or ~/.bashrc to persist)
export POSTIZ_API_KEY=your_api_key_here
Obtain your API key:
-
Visit postiz.com → Sign up for free -
Navigate to Settings → API Keys → Copy your key
Verify installation:
postiz integrations:list
This returns all connected social accounts as JSON. An empty array [] indicates that TikTok has not yet been connected.
Connecting TikTok to Postiz
-
Go to postiz.com → Integrations → Add Channel → TikTok -
Authorize with your TikTok account -
Run postiz integrations:listagain to see your integration ID:
[
{
"id": "clx9abc123",
"provider": "tiktok",
"name": "My TikTok Account",
"picture": "https://..."
}
]
Copy the id value. It is required for every posts:create command.
Core CLI Commands for TikTok
# Upload slides (PNG files), get back CDN URLs
SLIDE1=$(postiz upload ./output/slide_01.png | jq -r '.path')
SLIDE2=$(postiz upload ./output/slide_02.png | jq -r '.path')
SLIDE3=$(postiz upload ./output/slide_03.png | jq -r '.path')
# Schedule a slideshow post — pass multiple -m flags for each slide
postiz posts:create \
-c "I saved \$5k in 6 months doing this 💰 #personalfinance #moneytips" \
-m "$SLIDE1" -m "$SLIDE2" -m "$SLIDE3" \
-s "2025-04-21T09:00:00Z" \
-i "clx9abc123"
# List all scheduled posts
postiz posts:list
# Check TikTok-specific settings available
postiz integrations:settings clx9abc123
Every command outputs structured JSON, making it easy to parse in scripts or pipe into other tools.
Batch Scheduling from schedule.json
// batch-schedule.js
// Reads schedule.json, uploads each slide set, schedules via Postiz Agent CLI
import { execSync } from 'child_process'
import { readFileSync } from 'fs'
const INTEGRATION_ID = process.env.TIKTOK_INTEGRATION_ID
const schedule = JSON.parse(readFileSync('./schedule.json', 'utf-8'))
for (const post of schedule) {
// 1. Upload each PNG slide, collect CDN URLs
const slideFlags = post.slides.map(slide => {
const result = JSON.parse(execSync(`postiz upload ${slide}`).toString())
return `-m "${result.path}"`
}).join(' ')
// 2. Schedule slideshow post via Postiz Agent
execSync(
`postiz posts:create \
-c "${post.caption}" \
${slideFlags} \
-s "${post.scheduledAt}" \
-i "${INTEGRATION_ID}"`,
{ stdio: 'inherit' }
)
console.log(`✓ Scheduled: ${post.slides.length} slides at ${post.scheduledAt}`)
}
Accompanying schedule.json:
[
{
"slides": ["./output/mon_01.png", "./output/mon_02.png", "./output/mon_03.png", "./output/mon_04.png", "./output/mon_05.png", "./output/mon_06.png"],
"caption": "I saved $5k in 6 months doing this 💰 #personalfinance",
"scheduledAt": "2025-04-21T09:00:00Z"
},
{
"slides": ["./output/tue_01.png", "./output/tue_02.png", "./output/tue_03.png", "./output/tue_04.png", "./output/tue_05.png", "./output/tue_06.png"],
"caption": "Stop putting money in these 3 things 🚫 #moneytips",
"scheduledAt": "2025-04-22T09:00:00Z"
},
{
"slides": ["./output/wed_01.png", "./output/wed_02.png", "./output/wed_03.png", "./output/wed_04.png", "./output/wed_05.png", "./output/wed_06.png"],
"caption": "The money trap nobody warns you about 😮 #finance",
"scheduledAt": "2025-04-23T09:00:00Z"
}
]
Execute:
TIKTOK_INTEGRATION_ID=clx9abc123 node batch-schedule.js
One command schedules an entire week of content.
Stage 6: Publishing as TikTok Drafts to Avoid Spam Detection
“
Core question: Why does direct API publishing risk account restrictions, and how does draft-mode publishing protect your reach?
This is the most overlooked component of any TikTok automation setup. If you push posts directly via API at scheduled times from a server IP, TikTok’s systems will eventually flag the pattern as bot behavior—resulting in reduced reach, shadow restrictions, or account flags.
Why Draft Mode Matters
When auto-publishing via API, TikTok observes:
-
A server IP initiating the post -
Consistent robotic posting intervals -
No human interaction before the post goes live
When publishing from Drafts, TikTok observes:
-
Slides land silently in your TikTok Drafts -
You open the app at peak time, review the draft, and tap Post -
From TikTok’s perspective: a human published from a real device on a real network -
No server fingerprint on the actual publish action
This single change makes a significant difference for account health, especially for new accounts or high-frequency publishing schedules.
The Hybrid Workflow
[generate-slides.js] → PNG slides (slide_01.png ... slide_06.png)
↓
[tiktok-draft-upload.js] → Upload slides to TikTok Drafts via API
↓
[Postiz Notify mode] → Sends push notification at peak time
↓
[You open TikTok app] → Drafts → Review → Tap Post
Postiz manages the editorial calendar and reminder. The actual publish action comes from your device, which registers as a clean signal to the algorithm.
Uploading PNG Slides to TikTok Drafts
Option 1: Draft inside Postiz (retained in Postiz, not published)
Use the -t draft flag:
# Upload video first
RESULT=$(postiz upload video.mp4)
VIDEO_URL=$(echo "$RESULT" | jq -r '.path')
# Create post as draft
postiz posts:create \
-c "Your caption #fyp" \
-m "$VIDEO_URL" \
-s "2026-04-20T10:00:00Z" \
-t draft \
-p tiktok \
--settings '{
"title": "Video title",
"privacy_level": "PUBLIC_TO_EVERYONE",
"duet": false,
"stitch": false,
"comment": true,
"autoAddMusic": "no",
"brand_content_toggle": false,
"brand_organic_toggle": false,
"video_made_with_ai": false,
"content_posting_method": "DIRECT_POST"
}' \
-i "tiktok-integration-id"
The post sits in Postiz as a draft and will not publish until you change its status. Use postiz posts:status <id> --status schedule to queue it for publishing, or posts:delete to discard.
Option 2: Push to TikTok Inbox (draft inside TikTok app)
If you want the post to appear in the TikTok app as a pending draft you finalize on your phone, set content_posting_method to "UPLOAD":
postiz posts:create \
-c "Caption shown when you open TikTok app" \
-m "$VIDEO_URL" \
-s "2026-04-20T10:00:00Z" \
-p tiktok \
--settings '{
"privacy_level": "SELF_ONLY",
"content_posting_method": "UPLOAD"
}' \
-i "tiktok-integration-id"
When Postiz “publishes” this, TikTok delivers the video to the Inbox in the app. You open the app → tap the notification → finalize and post manually.
Configuring Postiz in Notify Mode
Set Postiz to Notify instead of Auto Publish. Postiz manages your editorial calendar and sends a push notification at the scheduled time reminding you to publish the draft from the app:
-
Postiz Dashboard → New Post -
Select TikTok → Add your caption and schedule the time -
Under Publish mode, select Notify (not Direct Post) -
Save
At the scheduled time, Postiz sends a mobile push notification: “Time to post your TikTok!” Open the app, find the draft waiting, and tap Post.
Author reflection: I ran direct API publishing for two weeks and watched average views drop from 5,000 to 200. After switching to draft mode, metrics recovered to baseline within three days. Platform detection of “bot-like” behavior is not theoretical—it is observable. The draft-mode compromise adds roughly thirty seconds per post, but the protection it provides for account health is non-negotiable.
Troubleshooting Common Issues
“
Summary: Most setup problems involve authentication, missing environment variables, or file size limits. Here are the fastest fixes.
| Issue | Likely Cause | Resolution |
|---|---|---|
POSTIZ_API_KEY environment variable is required |
Key not exported in current shell session | Add permanently: echo 'export POSTIZ_API_KEY=your_key_here' >> ~/.zshrc && source ~/.zshrc |
postiz integrations:list returns [] |
TikTok account not connected to Postiz | Go to postiz.com → Integrations → Add Channel → TikTok and authorize |
postiz upload fails |
Invalid API key or oversized file | Verify key validity; compress large PNGs with pngquant --quality=80-90 output/slide_*.png --ext .png --force |
| Scheduled post did not publish | Check postiz posts:list status field |
If status is failed, typically caused by expired TikTok OAuth token or rate limit. Re-authenticate and reschedule |
Important: Ensure your account has an established history of organic posting and is genuinely healthy before implementing high-frequency automated workflows.
Action Checklist / Implementation Steps
-
[ ] Search your niche on TikTok, filter by “Most Liked,” and browse 20–30 videos -
[ ] Download 3–5 viral slideshow videos using SnapTik -
[ ] Upload slideshow images to Claude Opus and run the hook extraction prompt -
[ ] Save generated hooks to Obsidian/Notion/Sheets to begin your hook library -
[ ] Request 5 Pinterest search terms from Claude -
[ ] Search Pinterest and download 10–15 portrait images; organize by niche folder -
[ ] Install Node.js dependencies: npm install canvas @napi-rs/canvas sharp -
[ ] Copy the generate-slides.jsscript; update image paths and copy lines -
[ ] Run node generate-slides.jsto produce PNG outputs -
[ ] Install Postiz CLI: npm install -g postiz -
[ ] Register at postiz.com, connect TikTok, and copy your integration ID -
[ ] Upload slides as drafts (using -t draftorcontent_posting_method: "UPLOAD") -
[ ] Set Postiz to Notify mode; publish manually from the TikTok app at peak times
One-Page Overview
| Stage | Tool | Input | Output | Time |
|---|---|---|---|---|
| Research | TikTok + SnapTik | Viral videos | Watermark-free video files | 30 min |
| Hook extraction | Claude Opus | Slideshow images/text | Hook library + Pinterest queries | 20 min |
| Asset sourcing | Search queries | 15–20 categorized images | 20 min | |
| Slide generation | Node.js Canvas | Images + copy | Six 1080×1920 PNG files | 5 min |
| Scheduling | Postiz Agent CLI | PNGs + caption + time | TikTok drafts / timed notifications | 10 min |
| Publication | TikTok App | Draft notification | Live post | 2 min/post |
Total investment: ~2 hours per week for 30 posts.
FAQ
Q1: Can I use this workflow without programming experience?
Yes. The scripting components can be configured once by a developer or technically inclined team member. After initial setup, non-technical users only need to edit JSON files and run simple commands. Pinterest downloading and Claude prompting require no code at all.
Q2: Why use Node.js instead of Canva?
Scripting enables batch production and visual consistency. When generating thirty slide sets at once, manual design in Canva becomes a bottleneck. The script operationalizes design decisions that have already been made.
Q3: Are there copyright concerns with Pinterest images?
Images on Pinterest are owned by their original creators. Prioritize images clearly uploaded for sharing, or consider alternatives from Unsplash, Pexels, or Pixabay for explicitly licensed content.
Q4: Can Claude Opus be replaced with another AI model?
Yes. Any multimodal model capable of image analysis with sufficient context window can perform hook extraction. The critical element is the prompt structure, not the specific model provider.
Q5: Why publish from drafts instead of direct scheduling?
TikTok employs detection mechanisms for automated behavior. Publishing directly from a server IP risks identification as bot activity, leading to reduced distribution. Draft mode ensures the final publish action originates from a real device.
Q6: Which niches work best with this approach?
Any visually representable vertical: personal finance, fitness, education, lifestyle, travel, food. The core requirement is that the content can be structured as hook → points → call-to-action within a slideshow format.
Q7: Will posting 30 times per week fatigue my audience?
Quality matters more than quantity. Treat the 30 posts as a portfolio where 5–10 are primary bets and the remainder are experiments testing different hooks and visual styles. Performance data will indicate where to concentrate effort.
Q8: What happens if TikTok changes its algorithm?
The core methodology—learning from proven content, batch production, and data-driven optimization—transcends any single platform’s algorithm. Specific tools and implementation details may need adjustment, but the underlying system remains valid.

