Skip to content

Instantly share code, notes, and snippets.

@homelab-alpha
Last active November 14, 2025 18:28
Show Gist options
  • Select an option

  • Save homelab-alpha/e0f265a9c9b20ca786bce2327ce87060 to your computer and use it in GitHub Desktop.

Select an option

Save homelab-alpha/e0f265a9c9b20ca786bce2327ce87060 to your computer and use it in GitHub Desktop.
Clear persistent or ghost GitHub notifications — A step-by-step guide to force hidden notifications into view so they can be dismissed manually.

🛠️ Fixing GitHub Ghost Notifications

Ghost notifications on GitHub can be frustrating. These are notifications that continue to show up in your notification count, even though they appear dismissed or no longer exist. This step-by-step guide will help you completely clear them from your GitHub notifications panel.

🔍 What Are "Ghost Notifications"?

Ghost notifications are lingering alerts in your GitHub notification count that won't go away — often caused by:

  • Archived or hidden notifications that are still marked as unread
  • Notifications from deleted repositories or issues
  • Incomplete dismissal due to GitHub UI bugs or sync issues

Important

There are several types of GitHub ghost notifications, and each may require a different solution.

This guide builds on this GitHub comment, which I’ve expanded with additional details and clearer explanations. The method described here helped me successfully remove ghost notifications.

The Optional/Advanced method draws from the official GitHub documentation. You can use:

  • cURL
  • JavaScript
  • GitHub CLI

The Community section includes additional solutions shared by other GitHub users, which may also work for you.

⚠️ This guide reflects my personal experience and is provided "as is".


✅ Step-by-Step Instructions

1. Go to the GitHub Notification Center

Visit https://github.com/notifications and log in if you haven’t already.

Tip

Before dismissing notifications, mark important ones as Saved. You can revisit them anytime from your Saved tab in the Notification Center.

If you see any visible notifications, make sure to read and dismiss them before continuing.

2. Move Archived Notifications to the Inbox

  1. In the left sidebar, click Done.
  2. Click Select all — this selects up to 25 notifications.
  3. Click → Move to Inbox.
  4. Refresh the page using F5 and/or Ctrl+R, then repeat steps 2 and 3 until you've moved at least 50 notifications to your Inbox.

3. Dismiss All Notifications from the Inbox

  1. In the left sidebar, click Inbox.
  2. Click Select all.
  3. If prompted with options like Done, Unsubscribe, and Selected all 50 notifications, click Select all 50 notifications to ensure everything is selected.
  4. Click Done to dismiss all selected notifications.

🎉 Done

By following these steps, you can remove persistent or "ghost" GitHub notifications that won’t disappear on their own. This method forces hidden or archived notifications into view so they can be manually dismissed — without needing the GitHub CLI or other advanced tools.

🧼 Still Seeing Ghost Notifications?

If the ghost notification count remains:

  • Repeat steps 2 and 3 under "Move Archived Notifications to the Inbox" until you’ve moved 100 or more notifications. This ensures all hidden or ghost notifications are surfaced and can be removed.
  • As a last resort, move all remaining notifications to your Inbox and dismiss them from there.

If none of these work, continue with the advanced options below.


🧪 Using GitHub REST API Endpoints (Optional/Advanced)

If the UI steps didn’t fully clear your ghost notifications, or if you prefer a programmatic approach, you can use the GitHub REST API to manage your notifications directly.

🧷 References

Important

🔐 Your token must include the notifications scope

When creating a new Personal Access Token (Classic), scroll down to the Notifications section and check the Access notifications option.

notifications_access_notifications_option

For security purposes, always set an expiration date for the token.

⏳ By default, the expiration is set to 30 days.


💻 Example API Calls

✅ Mark All Notifications as Read

Tip

Before dismissing all notifications, mark important ones as Saved. You can revisit them anytime from your Saved tab in the Notification Center.

curl -L \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/notifications \
  -d '{"last_read_at":"2022-06-10T00:00:00Z","read":true}'

Note

Replace <YOUR-TOKEN> with a valid Personal Access Token that includes the notifications scope.

The last_read_at field sets the timestamp GitHub will treat as your most recent "read" point for notifications. This allows you to control which notifications are marked as read.

For complete reference, see the Mark notifications as read documentation.


🧹 Mark a Specific Repository Notifications as Read

curl -L \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/notifications \
  -d '{"last_read_at":"2019-01-01T00:00:00Z"}'

Note

Replace <YOUR-TOKEN> with a valid Personal Access Token that includes the notifications scope.

Replace OWNER and REPO with the GitHub username (owner) and repository name. These values are not case-sensitive. Example: https://api.github.com/repos/homelab-alpha/docker/notifications \

The last_read_at field sets the timestamp GitHub will treat as your most recent "read" point for notifications. This allows you to control which notifications are marked as read from that specific repository.

For complete reference, see the Mark repository notifications as read documentation.


📨 Mark a Notification Thread as Read/Done

1. 📬 List Notifications for the Authenticated User

First, retrieve all current notifications for your account with the following command:

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/notifications

Note

Replace <YOUR-TOKEN> with a valid Personal Access Token that includes the notifications scope.

If the response from GitHub is an empty array ([]), it means there are currently no notifications.

For the full reference, see List notifications for the authenticated user documentation.

When you send this request, GitHub returns a JSON response containing your notifications. If you’d like to see an example of the full cURL response, click below to expand:

Example: Full cURL Response (click to expand)

[
  {
    "id": "58392017462",
    "unread": true,
    "reason": "assign",
    "updated_at": "2025-11-07T05:12:58Z",
    "last_read_at": "2025-11-07T05:12:19Z",
    "subject": {
      "title": "chore(deps): update ghcr.io/amir20/dozzle docker tag to v8.14.7",
      "url": "https://api.github.com/repos/homelab-alpha/docker/pulls/170",
      "latest_comment_url": "https://api.github.com/repos/homelab-alpha/docker/pulls/170",
      "type": "PullRequest"
    },
    "repository": {
      "id": 918472305,
      "node_id": "R_kgDOLh3ZcW",
      "name": "docker",
      "full_name": "homelab-alpha/docker",
      "private": false,
      "owner": {
        "login": "homelab-alpha",
        "id": 740928516,
        "node_id": "U_J8fQm2VxRz",
        "avatar_url": "https://avatars.githubusercontent.com/u/740928516?v=4",
        "gravatar_id": "",
        "url": "https://api.github.com/users/homelab-alpha",
        "html_url": "https://github.com/homelab-alpha",
        "followers_url": "https://api.github.com/users/homelab-alpha/followers",
        "following_url": "https://api.github.com/users/homelab-alpha/following{/other_user}",
        "gists_url": "https://api.github.com/users/homelab-alpha/gists{/gist_id}",
        "starred_url": "https://api.github.com/users/homelab-alpha/starred{/owner}{/repo}",
        "subscriptions_url": "https://api.github.com/users/homelab-alpha/subscriptions",
        "organizations_url": "https://api.github.com/users/homelab-alpha/orgs",
        "repos_url": "https://api.github.com/users/homelab-alpha/repos",
        "events_url": "https://api.github.com/users/homelab-alpha/events{/privacy}",
        "received_events_url": "https://api.github.com/users/homelab-alpha/received_events",
        "type": "User",
        "user_view_type": "public",
        "site_admin": false
      },
      "html_url": "https://github.com/homelab-alpha/docker",
      "description": "Explore the world of containerization with Docker and Docker Compose. These powerful tools package, distribute, and manage containerized applications.",
      "fork": false,
      "url": "https://api.github.com/repos/homelab-alpha/docker",
      "forks_url": "https://api.github.com/repos/homelab-alpha/docker/forks",
      "keys_url": "https://api.github.com/repos/homelab-alpha/docker/keys{/key_id}",
      "collaborators_url": "https://api.github.com/repos/homelab-alpha/docker/collaborators{/collaborator}",
      "teams_url": "https://api.github.com/repos/homelab-alpha/docker/teams",
      "hooks_url": "https://api.github.com/repos/homelab-alpha/docker/hooks",
      "issue_events_url": "https://api.github.com/repos/homelab-alpha/docker/issues/events{/number}",
      "events_url": "https://api.github.com/repos/homelab-alpha/docker/events",
      "assignees_url": "https://api.github.com/repos/homelab-alpha/docker/assignees{/user}",
      "branches_url": "https://api.github.com/repos/homelab-alpha/docker/branches{/branch}",
      "tags_url": "https://api.github.com/repos/homelab-alpha/docker/tags",
      "blobs_url": "https://api.github.com/repos/homelab-alpha/docker/git/blobs{/sha}",
      "git_tags_url": "https://api.github.com/repos/homelab-alpha/docker/git/tags{/sha}",
      "git_refs_url": "https://api.github.com/repos/homelab-alpha/docker/git/refs{/sha}",
      "trees_url": "https://api.github.com/repos/homelab-alpha/docker/git/trees{/sha}",
      "statuses_url": "https://api.github.com/repos/homelab-alpha/docker/statuses/{sha}",
      "languages_url": "https://api.github.com/repos/homelab-alpha/docker/languages",
      "stargazers_url": "https://api.github.com/repos/homelab-alpha/docker/stargazers",
      "contributors_url": "https://api.github.com/repos/homelab-alpha/docker/contributors",
      "subscribers_url": "https://api.github.com/repos/homelab-alpha/docker/subscribers",
      "subscription_url": "https://api.github.com/repos/homelab-alpha/docker/subscription",
      "commits_url": "https://api.github.com/repos/homelab-alpha/docker/commits{/sha}",
      "git_commits_url": "https://api.github.com/repos/homelab-alpha/docker/git/commits{/sha}",
      "comments_url": "https://api.github.com/repos/homelab-alpha/docker/comments{/number}",
      "issue_comment_url": "https://api.github.com/repos/homelab-alpha/docker/issues/comments{/number}",
      "contents_url": "https://api.github.com/repos/homelab-alpha/docker/contents/{+path}",
      "compare_url": "https://api.github.com/repos/homelab-alpha/docker/compare/{base}...{head}",
      "merges_url": "https://api.github.com/repos/homelab-alpha/docker/merges",
      "archive_url": "https://api.github.com/repos/homelab-alpha/docker/{archive_format}{/ref}",
      "downloads_url": "https://api.github.com/repos/homelab-alpha/docker/downloads",
      "issues_url": "https://api.github.com/repos/homelab-alpha/docker/issues{/number}",
      "pulls_url": "https://api.github.com/repos/homelab-alpha/docker/pulls{/number}",
      "milestones_url": "https://api.github.com/repos/homelab-alpha/docker/milestones{/number}",
      "notifications_url": "https://api.github.com/repos/homelab-alpha/docker/notifications{?since,all,participating}",
      "labels_url": "https://api.github.com/repos/homelab-alpha/docker/labels{/name}",
      "releases_url": "https://api.github.com/repos/homelab-alpha/docker/releases{/id}",
      "deployments_url": "https://api.github.com/repos/homelab-alpha/docker/deployments"
    },
    "url": "https://api.github.com/notifications/threads/58392017462",
    "subscription_url": "https://api.github.com/notifications/threads/58392017462/subscription"
  }
]

2. 🔎 Identify the Notification Thread

In the JSON output, locate the notification thread you want to mark as read. The repository.full_name field shows the GitHub username and repository name, the url field contains the thread ID.

Example:

[
  {
    "repository": {
      "full_name": "homelab-alpha/docker"
    },
    "url": "https://api.github.com/notifications/threads/58392017462"
  }
]

Here, the thread ID is 58392017462.

3. 🧹 Mark a Specific Thread as Read/Done

Once you have the thread ID, send a DELETE request to mark it as done:

curl -L \
  -X DELETE \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/notifications/threads/THREAD_ID

Note

Replace <YOUR-TOKEN> with a valid Personal Access Token that includes the notifications scope.

Replace THREAD_ID with the numeric ID from the url field in your notifications response. For example, if your notification JSON shows:

"url": "https://api.github.com/notifications/threads/58392017462"

the THREAD_ID is 58392017462.

For the full reference, see Mark a thread as done documentation


🌐 Options from the GitHub Community

The following are alternative solutions proposed by members of the GitHub community. In addition to the REST API, you may consider using the official GitHub CLI or other community-driven methods.

🧷 References

💡 Community-Suggested Fixes

@emeryao
Copy link

emeryao commented Sep 29, 2025

@homelab-alpha
Copy link
Author

https://github.com/orgs/community/discussions/174283#discussioncomment-14473564 works for me

Hi @emeryao, thanks for the tip! 😊

I'm aware that it's also possible via the GitHub CLI; I've come across a few approaches, including standalone scripts and the gh-gonest plugin.

That said, my approach doesn't require the GitHub CLI or any plugins. It's quick and simple without any additional tools.

@emeryao
Copy link

emeryao commented Sep 29, 2025

A google search result led me to your awesome guide and I tried all the steps but with no luck
and I found another workaround with the gh cli so I posted back here that I hope more others facing the same issue may got some help

@homelab-alpha
Copy link
Author

homelab-alpha commented Sep 29, 2025

@emeryao, Thanks for letting me know that this no longer works. It was still working for me a few days ago.

EDIT:

Here is the comment on which I based my guide on:

@shaunlebron
Copy link

I would replace this whole page with this:

gh api notifications | jq '.[] | { id, title: .subject.title, repo: .repository.full_name }'
gh api --method DELETE notifications/threads/$ID # <-- replace with issue ID

from @emeryao’s link to https://github.com/orgs/community/discussions/174283#discussioncomment-14473564

@homelab-alpha
Copy link
Author

Hi @shaunlebron, I did some further research. The method I described above in the guide still seems to work after reviewing a large number of issues and discussions.

That’s why I added an Optional/Advanced section for myself. In the GitHub documentation of REST API endpoints for notifications, you can see that there are several ways to do this, such as:

  • cURL
  • JavaScript
  • GitHub CLI

I personally chose cURL, simply because the terminal is available on almost every PC. In addition, I don’t have GitHub CLI installed on every device I use, and it’s not always possible to do so.

Conclusion: I’m not going to change this page just because someone disagrees with the solutions I provide.

@shaunlebron
Copy link

@homelab-alpha thanks, great work, and sorry! the curl commands didn’t work for me for some reason

@homelab-alpha
Copy link
Author

@shaunlebron, I have added additional information and options from the GitHub community to the guide. Hopefully, this makes the guide clearer and easier to use.

@fdwr
Copy link

fdwr commented Oct 2, 2025

Yay, this was the ticket to get rid of the persistent ycombinator hack notification (the repo was deleted, and clicking on unread notifications showed an empty list despite the number saying there was 1 unread), after generating a classic token (the new token is opaque what permissions I need to add to it) and updating the last_read_at to today:

curl -L \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/notifications \
  -d '{"last_read_at":"2025-10-01T00:00:00Z","read":true}'

@quantuminformation
Copy link

cant ever get rid of this one
image

repo:paradigm-notificaton/paradigm

@homelab-alpha
Copy link
Author

Hi @quantuminformation, Which options have you tried so far?

@quantuminformation
Copy link

the ones the UI should cover

@homelab-alpha
Copy link
Author

@quantuminformation, As mentioned in the guide, if it doesn’t work through the UI, try the advanced method Mark a specific repository notifications as read .

Since you’ve already specified which repository this concerns, I’ve prepared the cURL command for you.
You just need to generate a classic personal access token — make sure to enable the notifications scope.

notifications_access_notifications_option

Once you’ve generated the token, replace <YOUR-TOKEN> in the command below with your API token.
Then open your terminal, paste the command, and press Enter.

curl -L \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/paradigm-notificaton/paradigm/notifications \
  -d '{"last_read_at":"2019-01-01T00:00:00Z"}'

Hopefully, the “Ghost Notification” will disappear. 👻

If you need more information, check out the Advanced method method section and references.

@quantuminformation
Copy link

have a star thx

@homelab-alpha
Copy link
Author

have a star thx

@quantuminformation, did the cURL request work?

@quantuminformation
Copy link

i didnt get round to it yet

@piemot
Copy link

piemot commented Nov 7, 2025

These solutions didn't work for me. My ghost notification was from a repo that was deleted (plasma-network/plasma.to, if anyone's wondering). The only way that I found to clear it was to get the notification ID:

curl -L \
    -X GET \
    -H "Accept: application/vnd.github+json" \
    -H "Authorization: Bearer <token>" \
    -H "X-GitHub-Api-Version: 2022-11-28" \
    https://api.github.com/notifications

and then reset that specific ID:

curl -LI \
    -X PATCH \
    -H "Accept: application/vnd.github+json" \
    -H "Authorization: Bearer <token>" \
    -H "X-GitHub-Api-Version: 2022-11-28" \
    https://api.github.com/notifications/threads/<notification_id>

@homelab-alpha
Copy link
Author

Hi @piemot, thanks for the information. I’ve added it to the guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment