# Codemagic build finished notifications on your phone > Get a High-priority push notification when a Codemagic build fails, and optionally a quiet one when it succeeds, using a short publishing script in codemagic.yaml. - Company: Codemagic (https://www.justpush.io/recipes/codemagic) - Event: `build.finished` (Build finished) - Tags: CI/CD, Builds & CI - Install: https://studio.justpush.io/recipes/codemagic/build-finished - Web page: https://www.justpush.io/recipes/codemagic/build-finished ## Setup 1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL. 2. Codemagic has no outgoing webhooks, so copy the codemagic.yaml snippet from the setup notes below. It already contains your endpoint URL. 3. Add its two parts to each workflow you want to hear about: a last script step, and a publishing script. 4. Commit codemagic.yaml and run a build to test. 5. Codemagic can email you or post to Slack, but it can't call a webhook when a build ends. Its [publishing scripts](https://docs.codemagic.io/yaml-distributing/post-publish/) run after every build, pass or fail, so this recipe uses one to send the result to JustPush. 6. Add both parts below to each workflow in `codemagic.yaml` you want to hear about. The **last** script step marks the build as successful; the publishing script checks for that mark and posts the result. Replace `Acme Shop` with your app's name. 7. ```yaml 8. workflows: 9. ios-release: 10. name: iOS release 11. environment: 12. vars: 13. JUSTPUSH_APP_NAME: "Acme Shop" 14. scripts: 15. # ... your existing build steps ... 16. name: Mark build successful 17. script: touch ~/SUCCESS 18. publishing: 19. scripts: 20. name: Notify JustPush 21. script: | 22. if [ -f "$HOME/SUCCESS" ]; then STATUS=success; else STATUS=failure; fi 23. jq -n \ 24. --arg status "$STATUS" \ 25. --arg app "${JUSTPUSH_APP_NAME:-$CM_REPO_SLUG}" \ 26. --arg workflow "$CM_WORKFLOW_NAME" \ 27. --arg build_number "$BUILD_NUMBER" \ 28. --arg branch "$CM_BRANCH" \ 29. --arg tag "$CM_TAG" \ 30. --arg commit "$CM_COMMIT" \ 31. --arg commit_message "$(git -C "$CM_BUILD_DIR" log -1 --pretty=%s 2>/dev/null)" \ 32. --arg url "https://codemagic.io/app/$CM_PROJECT_ID/build/$CM_BUILD_ID" \ 33. '{event: "build.finished", status: $status, app: $app, workflow: $workflow, 34. build_number: $build_number, branch: $branch, tag: $tag, commit: $commit, 35. commit_message: $commit_message, url: $url}' \ 36. | curl -s -m 10 -X POST -H "Content-Type: application/json" --data @- "your webhook URL (shown in Studio after install)" || true 37. ``` 38. Only failed builds push by default (High priority). To also get a quiet push when a build succeeds, add `?all=1` to the URL in the snippet: 39. ``` 40. your webhook URL (shown in Studio after install)?all=1 41. ``` 42. Notes: 43. Codemagic doesn't run publishing scripts for builds that are **canceled or time out**, so those don't push. 44. The success mark only covers your script steps. If a built-in publisher such as App Store Connect or Google Play fails, this push can't tell; Codemagic's own email or Slack notifications cover that. 45. The snippet uses `jq` and `git`, as Codemagic's own publishing examples do. The `|| true` keeps a JustPush hiccup from failing your build. 46. The request is unsigned (`verify: none`), so 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 // Codemagic → build finished // Fires when the "Notify JustPush" publishing script from INSTALL.md reports a // "build.finished" event. Codemagic has no outgoing webhooks, so the snippet sends it. // Docs: https://docs.codemagic.io/yaml-distributing/post-publish/ // The snippet reports "success" or "failure". Failures push by default; successes need ?all=1. const STATUSES = { failure: { emoji: "❌", verb: "failed", priority: 1, always: true }, // broken build: needs you soon success: { emoji: "✅", verb: "succeeded", priority: -1, always: false }, // good news, only with ?all=1 } // Look a key up in a table without tripping over inherited names like "toString". function pick(table, key, fallback) { return typeof key === "string" && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback } // The snippet sends plain strings; treat blanks as missing. function text(value) { if (typeof value === "number" && Number.isFinite(value)) return String(value) return typeof value === "string" && value.trim() ? value.trim() : null } // Only link to real http(s) URLs. function link(url, cta) { return typeof url === "string" && /^https?:\/\//.test(url) ? [{ cta, url }] : [] } function handleRequest(request) { const event = request.body && typeof request.body === "object" ? request.body : {} // Guard: only this recipe's event, so other snippets on this integration stay quiet. if (event.event !== "build.finished") { console.log(`Ignoring Codemagic event "${event.event ?? "unknown"}"`) return null } // ?all=1 on the URL in the snippet also sends quiet pushes for successful builds. const all = ["1", "true", "yes"].includes(String(request.query?.all ?? "").toLowerCase()) const status = pick(STATUSES, event.status, null) if (!status || (!status.always && !all)) { console.log(`Skipping Codemagic build status "${event.status ?? "unknown"}"`) return null } const app = text(event.app) ?? "Your app" const number = text(event.build_number) const where = text(event.branch) ?? (text(event.tag) ? `tag ${text(event.tag)}` : null) const subject = (text(event.commit_message) ?? "").split("\n")[0] return { title: `${status.emoji} ${app} build${number ? ` #${number}` : ""} ${status.verb}`, message: [text(event.workflow), where].filter(Boolean).join(" · ") + (subject ? ` — ${subject}` : "") || "Codemagic build finished", topic: "Codemagic", priority: status.priority, buttons: link(event.url, "View build"), } } ``` ## Codemagic build.finished webhook payload (sample) ```json { "app": "Acme Shop", "tag": "", "url": "https://codemagic.io/app/5f1a2b3c4d5e6f7a8b9c0d1e/build/64f0a1b2c3d4e5f6a7b8c9d0", "event": "build.finished", "branch": "main", "commit": "564b61ebdd403d28b5dc616a12ce160b91585b5b", "status": "failure", "workflow": "iOS release", "build_number": "57", "commit_message": "Add checkout screen" } ``` ## 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 Codemagic 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.