github gitroomhq/postiz-app v2.24.0

4 hours ago

Important

This release addresses the security vulnerabilities PSA-2026-TD98KY and PSA-2026-P8W1J0, all users are recommended to upgrade immediately.

Highlights

This is a large release. The headline features are YouTube video clipping, a TikTok for Business provider, Sign in with Apple, a pluggable payment provider layer with RevenueCat alongside Stripe, and a much deeper MCP / agent surface (file upload widget, ChatGPT app, one-click Claude connector). Under the hood the publishing workflow gained heartbeats so hung activities are retried instead of stalling, and roughly forty provider-level bugs were fixed.

Important

This release adds new Prisma models and several new environment variables, and ships new Temporal workflow versions. See Upgrade notes before deploying.

✨ Features

Clipping — YouTube video → vertical clips → draft posts

  • Video clipping workflow — paste a YouTube URL and get back captioned vertical clips that land in the media library, optionally as draft posts on selected channels (#2104)
    • Choose how many clips (1–10) and how the 16:9 source lands on a vertical canvas (crop or blur)
    • Runs as a dedicated Temporal workflow with ingest and clipping activities on RunPod Serverless, using Deepgram to transcribe videos with no usable captions
    • Exposed as MCP tools with an interactive widget, so it can be driven from Claude and ChatGPT
  • Clipping endpoints on the public APIPOST /public/v1/clipping, GET /public/v1/clipping and GET /public/v1/clipping/:id (#2111)

New channels and channel features

  • TikTok for Business provider — a separate channel type for TikTok Business accounts, with music selection, random music and location tagging (#1897, #1908)
  • Provider visibility and migration controlsHIDDEN_PROVIDERS hides a provider from the add-channel screen, and MIGRATE_PROVIDERS (old:new) routes a reconnect of the old provider through the new one and migrates the channel in place
  • X (Twitter) articles — long-form article publishing support in the X provider and launch editor
  • Farcaster: Neynar managed signers — migrated off SIWN to Neynar managed signers, fixing the broken login state; the approval QR now opens in a modal instead of a blank tab (#2078, #2080)
  • Reddit subreddit search now resolves a pasted r/name or full subreddit URL (#2116)
  • Facebook background presets, Instagram collaborators and TikTok settings handling were tightened across the fix sweep below

Accounts, auth and billing

  • Sign in with Apple — web sign-in via a Services ID plus .p8 key, and native mobile sign-in via the iOS bundle id
  • Pluggable payment providers — payment handling moved behind a provider interface and manager, with RevenueCat added next to Stripe for App Store / Google Play subscriptions from the mobile app
  • Delete account — self-service account deletion from settings and from the FAQ page
  • Better onboarding flow for new accounts
  • Post reminders
  • Repeated posts — repeat handling reworked end to end (workflow v1.1.0)
  • Organization switching while impersonating (#1866)
  • Clearer active account/org indication for users who have several accounts on the same email (#1814)
  • Billing: the real prorated upgrade amount is shown instead of $0 (#1904), and cancellation emails now go to the customer rather than an internal address (#1782)

AI agent and MCP

  • Upload widget — upload local files from Claude and ChatGPT straight into the media library (#2099)
  • ChatGPT app served on its own /mcp-oauth-chatgpt issuer, with ChatGPT Enterprise domain restrictions via verified email claims
  • One-click Claude connector, Claude Dynamic Client Registration (RFC 7591) with a DCR_VERIFIED_DOMAINS redirect allowlist (#2091), and client_secret_basic accepted on the token endpoint (#2093)
  • New agent tools: list posts aligned with the List Posts API (#1816), update post settings (#1877), plus clipping, video status and upload widget tools
  • MCP email restrictions and localhost support for local MCP clients

Public API

  • PUT /public/v1/posts/:id/settings — update a post's settings (#1817)
  • GET /public/v1/users — list the organization's users
  • Superuser debug endpointsGET /public/v1/debug/account, /debug/channels, /debug/activity and /debug/posts/:id, behind a super-admin guard, with an x-postiz-org override and an x-postiz-include-deleted header for dispute and support evidence (#2096)

Admin and analytics

  • Admin stats: unique publishing/scheduled users per platform (#1843), unique publishing/scheduled channels per platform (#1849), and active orgs per post creation source (#1997)
  • Admins can apply organization-level changes while impersonating, including switching orgs

Media

  • Optional media normalization — when RunPod is configured, web uploads are transcoded to 1080p h264 mp4 (images downsized) in the background; the media record reports processing until the normalized file replaces the original
  • Veo3 video generation migrated from kie.ai to EvoLink (Seedance) (#1956)
  • AI video generation no longer hangs forever when the provider reports a failure (#1809)

🔧 Reliability and orchestration

  • Activity heartbeats — publishing activities now heartbeat, and the post workflow was versioned forward through v1.0.7 → v1.1.2 to use them:
    • v1.0.7/v1.0.8 introduce and fix heartbeating
    • v1.0.9 removes the fixed interval
    • v1.1.0 reworks repeat handling
    • v1.1.1 retries activities that never started on a heartbeat timeout (#1996)
    • v1.1.2 also retries on a heartbeat timeout with no heartbeat details (#2013)
  • Hung publishing activities now surface what they were waiting on instead of failing opaquely (#1965)
  • Pending + finalize flow extended to more platforms, reducing duplicate posts when a publish is interrupted
  • Non-main Temporal workers are now activity-only, so they no longer pick up workflow tasks (#1718)
  • Temporal SDK logs are routed through console so they reach Sentry (#1906)

🐛 Fixes

Facebook / Instagram / Threads

  • Video and reel analytics use video_insights, fixing a crash on a nonexistent field (#1669)
  • Reels metrics are requested for video post analytics (#2115)
  • Graph API errors surface in page analytics instead of caching an empty result (#2098)
  • (#200) permission errors map to a curated message (#1892)
  • Channels holding a non-page token are flagged as needing reconnection (#1881)
  • Meta Graph API bumped from v20.0 to v25.0 behind a shared constant (#1917, #1969)
  • Instagram: collaborators are sent on the carousel container rather than child items (#2088), untaggable collaborators are reported instead of "Unknown Error" (#1876), a leading @ is stripped from handles, "Media fetch failed" (2207052) is retryable (#1900), and a missing instagram_content_publish permission maps to a curated message (#1914)
  • Threads: the OAuth authorize URL uses threads.com (#1819), and post length is counted in UTF-8 bytes (#1946)

LinkedIn

  • Connecting a company page no longer hijacks the personal LinkedIn channel (#1767)
  • Pages are listed for Content Admins, not only Super Admins (#1808)
  • Analytics elements without a timeRange are skipped (#1769)

TikTok / YouTube

  • picture_size_check_failed message corrected and image sizes pre-checked (#1875)
  • YouTube: 403 forbidden upload errors map to a curated message (#1913), and the unverified-channel thumbnail error message is clearer (#1933)
  • YouTube and TikTok media reads request identity encoding (#1853)
  • TikTok music fix in the business provider

Pinterest

  • Pin analytics read from summary_metrics instead of lifetime_metrics (#1851)
  • Transient "Something went wrong on our end" errors are retried (#1907)
  • "Could not fetch the image" is treated as retryable (#1931)
  • The anti-spam pin block is retried instead of failing with "Unknown Error" (#1962)

Reddit / Bluesky / Slack / GMB / Hashnode / X

  • Reddit: SUBREDDIT_NOEXIST is retried rather than failing the post (#1886), subreddit names are stripped of leading/trailing slashes (#1930), and the settings type accepts only self, link, media (#1915)
  • Bluesky: the underlying error surfaces when preparation keeps failing (#1929), and a 5xx login failure no longer disconnects the channel (#2084)
  • Slack: chat.postMessage failures surface instead of the post being marked published (#2117), and video attachments are rejected at save time (#2118)
  • Google Business Profile: posts fail when Google returns REJECTED or an unconfirmed localPost (#1825), and Google's searchUrl is used as the post release URL (#2107)
  • Hashnode: moved to the live GraphQL endpoint and the current publishPost schema (#2108)
  • X: analytics no longer crash when a timeline page has no tweets (#1765)

Posts, webhooks and platform

  • Webhook payloads were always empty — the post is now resolved via a releaseId fallback (#2087)
  • Republishing a published post requires an explicit opt-in (#1841)
  • Post creation is rejected on soft-deleted channels (#1921)
  • Schedule-type saves carrying a past date are rejected (#1938)
  • Tags are attached on post creation after creating a tag in the modal (#1830)
  • Accepting a redundant invite to an organization the user already belongs to no longer errors (#1742)
  • The public API returns 404 instead of 500 when deleting a missing post (#1768)

Frontend

  • Duplicate "Are you sure?" dialogs after connecting a WordPress channel (#1641)
  • The org switcher dropdown stays clickable above modal screens (#1815)
  • The repeat interval no longer leaks between post modal opens (#1974)
  • Reconnect on a custom-fields channel opened a 404 page (#2085)
  • The Change Bot Picture media picker opens as a modal (#2083)
  • The hardcoded 5% trend badge was removed from provider analytics (#1970)
  • Mantine Autocomplete replaced with a native input in the customer modal (React 19 ref warning) (#2094)
  • The Chatbase widget is hidden while the creation modal is open

📈 Observability

  • Sentry gained searchable identity tags (user id, org id, Stripe customer id) on all telemetry (#1800, #1870, #1987), structured logs from the frontend and NestJS (#1918, #1977), the account email attached to bug reports instead of prompting for it (#1869), trace and session-replay sampling to stay inside quota (#2082), and no tracing on GET requests to the MCP streamable routes (#2100)

🧰 Developer experience

  • Unit, integration, workflow and E2E test bootstrapping with ReportPortal (#2039)
  • CODEOWNERS added (#1919); contributing guidelines updated for staging and for .env.example environment variables (#1901, #1975)
  • PR template now enforces a detailed # QA section
  • Security policy updated with current endpoints and a dispute policy (#1858), and GAdvisory scope broadened
  • Mastra and CopilotKit upgraded; packages with known security issues upgraded
  • docker-compose port conflict with PGAdmin fixed

Upgrade notes

Database. New Prisma models are added: Clipping, ClippingClip, and the mastra_* set backing the upgraded agent stack. Run your usual Prisma deploy step before starting the new backend.

Temporal. New post workflow versions (v1.0.7 – v1.1.2) plus new clipping, generate.video and process.media workflows ship in this release. Deploy the orchestrator so workers register them; existing in-flight executions keep running on their pinned versions.

New environment variables (all optional unless you use the feature):

Variable Purpose
APPLE_CLIENT_ID, APPLE_SERVICE_ID, APPLE_TEAM_ID, APPLE_KEY_ID, APPLE_PRIVATE_KEY, APPLE_BUNDLE_ID Sign in with Apple (web via Services ID + .p8, mobile via bundle id)
TIKTOK_BUSINESS_CLIENT_ID, TIKTOK_BUSINESS_CLIENT_SECRET TikTok for Business provider
NEYNAR_CLIENT_ID, NEYNAR_SECRET_KEY, NEYNAR_APP_FID, NEYNAR_APP_MNEMONIC, NEYNAR_SPONSOR_SIGNERS Farcaster via Neynar managed signers
RUNPOD_API_KEY, RUNPOD_ENDPOINT_ID Optional media normalization (requires STORAGE_PROVIDER="cloudflare")
RUNPOD_INGEST_ENDPOINT_ID, RUNPOD_CLIPPER_ENDPOINT_ID, DEEPGRAM_API_KEY Video clipping (also needs RUNPOD_API_KEY, OPENAI_API_KEY, Cloudflare storage)
EVOLINK_API_KEY Seedance AI video generation (replaces the kie.ai Veo3 path)
REVENUECAT_SECRET_KEY, REVENUECAT_WEBHOOK_SECRET, IN_APP_PURCHASE_REJECT_SANDBOX RevenueCat subscriptions; webhook at {BACKEND_URL}/payment/revenuecat
OPENAI_OAUTH_CLIENT_ID OAuth client for the ChatGPT app (verified email claims for Enterprise domain restrictions)
DCR_VERIFIED_DOMAINS Comma-separated redirect-domain allowlist for MCP Dynamic Client Registration; unset means any client can self-register
HIDDEN_PROVIDERS, MIGRATE_PROVIDERS Hide a provider from the add-channel screen / route reconnects of an old provider through a new one

Behaviour changes to be aware of:

  • Republishing an already-published post now requires an explicit opt-in.
  • Post creation against soft-deleted channels, schedule saves with a past date, and Slack video attachments are now rejected rather than silently accepted.
  • Meta Graph API calls moved from v20.0 to v25.0.
  • Payment webhooks are now served from a generic {BACKEND_URL}/payment/:provider route (/payment/stripe, /payment/revenuecat); the legacy /stripe webhook route is still served, so existing Stripe configurations keep working.

Contributors

@nevo-david, @giladresisi, @egelhaus

Full Changelog: v2.23.0...v2.24.0

Don't miss a new postiz-app release

NewReleases is sending notifications on new releases.