# Jira new comment notifications on your phone

> Get a push notification when someone comments on a Jira issue.

- Company: Jira (https://www.justpush.io/recipes/jira)
- Event: `comment_created` (Comment: created)
- Tags: Project management, Issues & tickets
- Install: https://studio.justpush.io/recipes/jira/new-comment
- Web page: https://www.justpush.io/recipes/jira/new-comment

## 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 Jira, go to Settings > System > WebHooks and click Create a WebHook (Jira admins only).
3. Paste your webhook URL (shown in Studio after install) as the URL. Optionally limit it with a JQL filter such as project = ABC.
4. Tick Comment: created and save.
5. Create an admin webhook under **Settings → System → WebHooks** and tick **Comment: created**. Use the JQL box (for example `project = SHOP`) to limit which issues push. Edited and deleted comments are ignored.
6. Admin webhooks can have a **Secret**, which Jira uses to sign each delivery (`X-Hub-Signature: sha256=…`), but JustPush doesn't check that signature yet, 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
// Jira → comment_created (new comment)
// Fires when someone comments on an issue in the projects (or JQL filter) your webhook covers.
// Docs: https://developer.atlassian.com/cloud/jira/platform/webhooks/

// Keep long text readable in a notification.
function clip(value, max = 120) {
    const text = typeof value === "string" ? value.replace(/\s+/g, " ").trim() : ""
    return text.length > max ? text.slice(0, max - 1) + "…" : text || null
}

// Comment bodies are usually plain text (wiki markup); if one arrives as Atlassian Document
// Format (a JSON tree), collect its text nodes instead.
function plain(node) {
    if (typeof node === "string") return node
    if (!node || typeof node !== "object") return ""
    const own = typeof node.text === "string" ? node.text : ""
    const kids = Array.isArray(node.content) ? node.content.map(plain).join(" ") : ""
    return [own, kids].filter(Boolean).join(" ")
}

// Only link to real http(s) URLs.
function link(url, cta) {
    return typeof url === "string" && /^https?:\/\//.test(url) ? [{ cta, url }] : []
}

// issue.self is the REST URL (https://acme.atlassian.net/rest/api/2/issue/10001); the browse
// link lives on the same site: https://acme.atlassian.net/browse/ABC-123.
function browse(issue) {
    const match = typeof issue?.self === "string" ? issue.self.match(/^(https?:\/\/.+?)\/rest\//) : null
    return match && typeof issue.key === "string" ? `${match[1]}/browse/${issue.key}` : null
}

function handleRequest(request) {
    const body = request.body && typeof request.body === "object" ? request.body : {}
    const comment = body.comment && typeof body.comment === "object" ? body.comment : null

    // Guard: only new comments.
    if (body.webhookEvent !== "comment_created" || !comment) {
        console.log(`Ignoring Jira "${body.webhookEvent ?? "unknown"}" event`)
        return null
    }

    const issue = body.issue ?? {}
    const who = comment.author?.displayName ?? "Someone"
    const summary = issue.fields?.summary
    const url = browse(issue)
    // Jump straight to the comment when we know its ID.
    const target = url && comment.id ? `${url}?focusedCommentId=${encodeURIComponent(comment.id)}` : url

    return {
        title: `💬 ${who} on ${issue.key ?? "an issue"}`,
        message: [clip(plain(comment.body)) ?? "New comment", typeof summary === "string" && summary ? `(${summary})` : null].filter(Boolean).join(" "),
        topic: "Jira",
        priority: -1, // Low — read it when you're back in Jira
        buttons: link(target, "Open comment"),
    }
}
```

## Jira comment_created webhook payload (sample)

```json
{
  "issue": {
    "id": "10231",
    "key": "SHOP-88",
    "self": "https://acme.atlassian.net/rest/api/2/issue/10231",
    "fields": {
      "status": {
        "id": "3",
        "name": "In Progress"
      },
      "project": {
        "id": "10000",
        "key": "SHOP",
        "name": "Webshop"
      },
      "summary": "Checkout total is off by one cent",
      "priority": {
        "id": "2",
        "name": "High"
      },
      "issuetype": {
        "id": "10004",
        "name": "Bug"
      }
    }
  },
  "comment": {
    "id": "10510",
    "body": "Found it — we round each line before summing. Fix incoming.",
    "self": "https://acme.atlassian.net/rest/api/2/issue/10231/comment/10510",
    "author": {
      "self": "https://acme.atlassian.net/rest/api/2/user?accountId=5b10a2844c20165700ede21g",
      "active": true,
      "accountId": "5b10a2844c20165700ede21g",
      "accountType": "atlassian",
      "displayName": "Sam Lee"
    },
    "created": "2026-09-28T11:46:51.000+0200",
    "updated": "2026-09-28T11:46:51.000+0200",
    "jsdPublic": true,
    "updateAuthor": {
      "accountId": "5b10a2844c20165700ede21g",
      "displayName": "Sam Lee"
    }
  },
  "timestamp": 1759052811000,
  "webhookEvent": "comment_created"
}
```

## 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 Jira 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.
