# Ghost post published notifications on your phone > Get a low-priority push notification when a post goes live on your Ghost site, including scheduled posts, with a button to read it. - Company: Ghost (https://www.justpush.io/recipes/ghost) - Event: `post.published` (Post published) - Tags: Websites & CMS, Content & publishing - Install: https://studio.justpush.io/recipes/ghost/post-published - Web page: https://www.justpush.io/recipes/ghost/post-published ## Setup 1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL. 2. In Ghost Admin, go to Settings > Advanced > Integrations and click Add custom integration (name it JustPush). 3. Click Add webhook, pick Post published as the event and paste your webhook URL (shown in Studio after install) as the target URL. 4. Leave the secret empty (JustPush doesn't check it yet) and save. 5. Pick **Post published** as the webhook event. Scheduled posts trigger it when they go live, not when you schedule them. 6. Want pages too? Add a second webhook for **Page published** with the same URL. 7. Ghost can sign webhooks with a secret (`X-Ghost-Signature`), but JustPush doesn't check that signature yet, so leave the secret empty and keep your endpoint URL private. ## Code Studio calls `handleRequest(request)` with the incoming webhook (`{ method, headers, body, query, raw }`) and sends the message object it returns. Returning `null` sends nothing. ```js // Ghost โ†’ post.published // Fires when a post is published on your Ghost site, including scheduled posts going live. // Also accepts page.published if you add that webhook too. // Docs: https://docs.ghost.org/webhooks // Who can read it, for anything other than a public post. const VISIBILITY = { members: "members only", paid: "paid members only", tiers: "selected tiers only", } // Ghost sends plain strings; treat blanks as missing. function text(value) { return typeof value === "string" && value.trim() ? value.trim() : null } function pick(table, key, fallback) { return Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback } // Only link to real http(s) URLs. function link(url, cta) { return typeof url === "string" && /^https?:\/\//.test(url) ? [{ cta, url }] : [] } function handleRequest(request) { const body = request.body && typeof request.body === "object" ? request.body : {} const kind = body.post ? "post" : body.page ? "page" : null const current = kind ? body[kind].current : null const previous = kind && body[kind].previous && typeof body[kind].previous === "object" ? body[kind].previous : {} // Guard: only a post or page going live. Newer Ghost versions name the event in the body; // otherwise it has to be published now and either new or not published before // (an edit to a live post has a "previous" without a status change). const published = body.event ? body.event === `${kind}.published` : current?.status === "published" && (Object.keys(previous).length === 0 || (typeof previous.status === "string" && previous.status !== "published")) if (!kind || !current || typeof current !== "object" || !published) { console.log(`Ignoring Ghost "${body.event ?? "unknown"}" event`) return null } const title = text(current.title) ?? `Untitled ${kind}` const author = text(current.primary_author?.name) ?? (Array.isArray(current.authors) ? text(current.authors[0]?.name) : null) const who = pick(VISIBILITY, current.visibility, null) return { title: kind === "page" ? "๐Ÿ“„ Page published" : "๐Ÿ“ฐ Post published", message: `"${title}"` + (author ? ` by ${author}` : "") + (who ? ` ยท ${who}` : ""), topic: "Ghost", priority: -1, // Low โ€” good to know, nothing to do buttons: link(current.url, kind === "page" ? "View page" : "Read post"), } } ``` ## Ghost post.published webhook payload (sample) ```json { "post": { "current": { "id": "6512c0ffee0000000000abcd", "url": "https://example.com/ten-tips-for-a-calmer-inbox/", "slug": "ten-tips-for-a-calmer-inbox", "tags": [ { "id": "6512c0ffee0000000000aaaa", "name": "Productivity", "slug": "productivity" } ], "uuid": "0b6c2d3e-4a5b-4c6d-8e9f-0a1b2c3d4e5f", "title": "Ten tips for a calmer inbox", "status": "published", "authors": [ { "id": "1", "name": "Jamie", "slug": "jamie" } ], "excerpt": "Small habits that add up.", "featured": false, "created_at": "2026-09-28T15:12:00.000Z", "updated_at": "2026-09-29T08:00:00.000Z", "visibility": "public", "published_at": "2026-09-29T08:00:00.000Z", "custom_excerpt": "Small habits that add up.", "primary_author": { "id": "1", "name": "Jamie", "slug": "jamie" } }, "previous": { "status": "draft", "updated_at": "2026-09-28T15:30:00.000Z", "published_at": null } }, "event": "post.published" } ``` ## FAQ ### Does this work on iPhone and Android? Yes. Install the JustPush app from the App Store or Google Play and sign in. Every phone signed in to your account gets the notification. ### Do I need to write code? No. Install the recipe in Studio, paste your webhook URL into Ghost and you are done. The code is there if you want to change the text, the sound or the buttons. ### Can I change what the notification says? Yes. After install the recipe's code is yours. Edit it in Studio and test it against the sample payload before you save. ### What does it cost? JustPush is free for 30 days. After that it's $19.99 a year, or $39.99 once. There is no extra charge for recipes.