107

I get Chrome notifications from several websites and they work when I don't even have any tabs open for those sites.

But sometimes I get these Chrome notifications when I am not at my desk or looking at my laptop.

As some of these notifications are useful to me, I would like to be able to access any that I have missed.

Is there a way to view the notification history?

4
  • 1
    Doesn't seem like it. Looking at this post (theverge.com/2015/10/14/9531133/…), they rearranged their notification policy and removed it from desktop to put it on individual webpages. The only thing to access new notifications is to click the bell on a google page.
    – Terry
    Feb 3, 2016 at 15:15
  • 1
    Seems like nope: productforums.google.com/forum/#!msg/chrome/xs9PflHTfho/… - very unfortunate.
    – LB--
    Jun 19, 2016 at 19:26
  • The only place I've found notifications as a list is if the website that fires them has them via their website. Chrome doesn't appear to collect them in something like chrome://notifications and they don't make it to the OS. Aug 2, 2016 at 14:44
  • Accept the valid answer @paradroid
    – Satheesh
    Aug 21, 2018 at 14:26

10 Answers 10

40

If you have a Mac, there is a way! 😄

Here's how the notifications list would look like:

Here's how the notifications list would look like.

All you have to do is:

1. In chrome, go to:

chrome://flags/

2. Look for:

Enable native notifications. Mac

3. Enable it, restart chrome, you are done. Enjoy!

EDIT:

  • You might not need to do the above anymore.

Starting in Chrome 59, notifications sent via the Notifications API or the chrome.notifications extensions API will be shown directly by the macOS native notification system instead of Chrome's own system. [source]

7
  • 11
    This doesn't answer the question of seeing notification history, just seeing notifications.
    – Bjorn
    Mar 4, 2017 at 0:35
  • 7
    @BjornTipling It does answer it. He is asking if he can see the notifications he missed while away and my method does exactly that. Mar 15, 2017 at 4:36
  • 1
    If you put the links as comments, I will add them to your post for you, @EsdrasLopez Apr 13, 2018 at 13:52
  • 1
    @user418150 I appreciate that, but I got the reputation now. :) Check the edits. Apr 14, 2018 at 17:49
  • 4
    The main problem here is that it only stores the notification if you don't click on it. Several times I have clicked on an interesting article title, only to have it fail to load, however, it still got removed from the notifications list. Usually the articles are too new to be Googled and often the notification title doesn't match the article title, so it gets lost in the bowels of the web.
    – tborzecki
    Sep 21, 2018 at 0:59
33

On MacOSX you will have Chrome directory located in Library/Application Support. Open terminal application and run next commands:

cd ~/Library/Application\ Support/Google/Chrome/Default/Platform\ Notifications/
ls -la

On Gnu/Linux (at least on Linux Mint), similarly you can find the log file(s) in /home/user/.config/google-chrome/Profile 1/Platform Notifications/ – jdmayfield

Now you will see files like this:

drwx------@  7 visi  staff   224 Jul 13 18:16 .
drwx------  75 visi  staff  2400 Jul 15 11:05 ..
-rw-------@  1 visi  staff   759 Jul 15 10:57 000003.log
-rw-------@  1 visi  staff    16 Jul 13 18:16 CURRENT
-rw-------@  1 visi  staff     0 Jul 13 18:16 LOCK
-rw-------@  1 visi  staff   147 Jul 13 18:16 LOG
-rw-------@  1 visi  staff    41 Jul 13 18:16 MANIFEST-000001

You can see the most recent one is 000003.log, so check it by next command:

tail -n 100 000003.log

And you will see last 100 items from this log. Then you can open chrome settings and disable that website notification.

Note that if you have several profiles in chrome, your path can be different, like this (Profile1 instead of Default):

cd ~/Library/Application\ Support/Google/Chrome/Profile\ 1/Platform\ Notifications/
7
  • 9
    This should be the accepted answer. :) Jan 12, 2019 at 14:45
  • 2
    Still working in 2019 (although the log needs a little interpreting). Great answer thanks
    – carpii
    Jun 23, 2019 at 0:31
  • 1
    On Linux (at least on Linux Mint), similarly you can find the log file(s) in /home/user/.config/google-chrome/Profile 1/Platform Notifications/
    – jdmayfield
    Jan 10, 2020 at 4:54
  • Any solution for Ubuntu? The log file I'm seeing on Ubuntu 18.04 in a similar location to this (~/.config/chrome-remote-desktop/chrome-profile/Default/Platform Notifications/000003.log) is empty. Jan 24, 2020 at 0:41
  • Update; try this for Ubuntu 18.04, but it's really hard to read, as it's a binary blob containing a bunch of readable ASCII chars/strings is all: tail -n 10 "/home/$USER/.config/google-chrome/Default/Platform Notifications/000003.log" Jan 24, 2020 at 0:45
26

If you are using MS-Windows, then go to %LocalAppData%\Google\Chrome\User Data\Default\Platform Notifications, there is a log file of past notifications.

6
  • 4
    good, but consider specifying path as "%LocalAppData%\Google\Chrome\User Data\Default\Platform Notifications" instead of hardcode. It perfectly works on any PC. Nov 18, 2017 at 14:04
  • 2
    In the UserData/-folder you might have to locate your profile folder first, such as "C:\Users\username\AppData\Local\Google\Chrome\UserData\Profile 1\Platform Notifications"
    – Maffelu
    Jan 4, 2018 at 7:55
  • 3
    This data is binary. How to read it?
    – Gaia
    Feb 14, 2018 at 16:39
  • 2
    On Chrome 71, and the log file is empty. Did this get disabled at some point?
    – James
    Jan 19, 2019 at 23:36
  • 4
    @Gaia I wondered the same thing and just whipped up some crappy Java code that does an acceptable job at deciphering most of it. I posted it below: superuser.com/a/1410742/778383 Mar 2, 2019 at 13:25
6

TL;DR:

For Ubuntu, jump down to the "final one-liner" TL;DR answer at the bottom.

Details:

This is modeled after @Andrey Bezpalenko's answer, but tested to be functional also on Ubuntu 18.04.

As is the case with his answer too, however, the output is pretty stinking ugly, as it's binary output with readable ASCII character strings intermingled in with the binary. Here are the steps:

  1. Find the latest log file (*.log) in the "Platform Notifications" directory for your Chrome installation:

     find ~ | grep --extended-regexp "google-chrome.{0,30}Platform Notifications.*\.log$" | tail -n 1
    

Sample Output:

    $ find ~ | grep --extended-regexp "google-chrome.{0,30}Platform Notifications.*\.log$" | tail -n 1
    find: ‘/home/gabriel/.cache/doc’: Permission denied
    /home/gabriel/.config/google-chrome/Default/Platform Notifications/000003.log

We can see we found the log file here: /home/gabriel/.config/google-chrome/Default/Platform Notifications/000003.log.

  1. View the last, let's say, 10 lines, or log entries, from this log file:

     tail -n 10 "/home/gabriel/.config/google-chrome/Default/Platform Notifications/000003.log"
    

Sample output of just the last 3 items (tail -n 3 "/home/gabriel/.config/google-chrome/Default/Platform Notifications/000003.log"). Notice how flippin' ugly this is to try to read and interpret!

    $ tail -n 3 "/home/gabriel/.config/google-chrome/Default/Platform Notifications/000003.log"
    o"link"dhttps://www.reddit.com/r/AskReddit/comments/est2b4/what_would_be_the_worst_thing_to_put_in_a_pi�ata/"correlation_id"$1b7b2ef8-3ebb-4532-81ec-f896e58edaff"
                                                                                                                                                                       message_type"lifecycle_post_suggestions" device_id"@a5df86650804f98993acc43b31efa4ec0c733485b8cef4d8fe64a01ad07e9e09"auto_dismiss_optionsobehavior"timed"dismiss_time_msI��{{X`�������hrz* p#https://www.reddit.com/#01019308@H����P�-X�-`�-hp���-��<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193�_Q��<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193�
                                                                                                                                                                  ��<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193��,����DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg�https://www.youtube.com/"�
    SpaceX In-Flight Abort Test"Recommended: NASA Video*�SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAo"nav"B/watch?v=mu5Ydz34oVc&feature=push-fr&attr_tag=WQZST9cYBH8yY01w%3A6"id"COvK+bnsmucCEJQB"attributionTag"WQZST9cYBH8yY01w:6{X`�������hrz*�p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg08@H�������hp�q�I���DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg�https://www.youtube.com/"�
    SpaceX In-Flight Abort Test"Recommended: NASA Video*�SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAo"nav"B/watch?v=mu5Ydz34oVc&feature=push-fr&attr_tag=WQZST9cYBH8yY01w%3A6"id"COvK+bnsmucCEJQB"attributionTag"WQZST9cYBH8yY01w:6{X`�������hrz*�p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg08@H�������`�hp������DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg�RESOURCES:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg

Or, just do all of the above in one single step:

tail -n 10 "$( find ~ | grep --extended-regexp "google-chrome.{0,30}Platform Notifications.*\.log$" | tail -n 1 )"

Or even better, also print out the path to the log file:

TL;DR: the final one-liner:

LOG_FILE="$( find ~ | grep --extended-regexp \
"google-chrome.{0,30}Platform Notifications.*\.log$" | tail -n 1 )"; \
echo -e "LOG_FILE=\"$LOG_FILE\"\n---------\n"; tail -n 10 "$LOG_FILE"

Further work:

Can anyone make this output look less horribly ugly? I'd like to see prior notifications in a more readable format!

Update 25 May 2020:

Here's one step closer to something useful: after running the "final one-liner" above, do this to extract just the ASCII chars from the binary, and remove extraneous spaces.

strings "$LOG_FILE" | sed -E 's/[ ]{8,}/\n/g'

First, strings extracts ASCII strings from the binary file. Then, the "'s'tream 'ed'itor", sed, 'g'lobally replaces all instances of 8 or more spaces in the 's'tring with a newline char, \n, since I noticed there were dozens if not hundreds of spaces in a row sometimes, which dramatically reduced readability. The -E in sed is to allow 'E'xtended regular expression searches.

Note that the one-liner command above already stored the file path into the LOG_FILE variable, so we are just going to re-use that variable here. See echo "$LOG_FILE" if you need to see what that variable holds.

After doing the above, you'll get something like this:

$ strings temp.txt | sed -E 's/[ ]{8,}/\n/g'
o"link"dhttps://www.reddit.com/r/AskReddit/comments/est2b4/what_would_be_the_worst_thing_to_put_in_a_pi
ata/"correlation_id"$1b7b2ef8-3ebb-4532-81ec-f896e58edaff"

message_type"lifecycle_post_suggestions" device_id"@a5df86650804f98993acc43b31efa4ec0c733485b8cef4d8fe64a01ad07e9e09"auto_dismiss_optionsobehavior"timed"dismiss_time_msI
{{X`
hrz* p#https://www.reddit.com/#01019308@H
<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193
<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193


<DATA:https_www.reddit.com_0p#https://www.reddit.com/#010193ARESOURCES:https_www.reddit.com_0p#https://www.reddit.com/#010193
DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg
https://www.youtube.com/"

SpaceX In-Flight Abort Test"Recommended: NASA Video*
SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAo"nav"B/watch?v=mu5Ydz34oVc&feature=push-fr&attr_tag=WQZST9cYBH8yY01w%3A6"id"COvK+bnsmucCEJQB"attributionTag"WQZST9cYBH8yY01w:6{X`
hrz*
p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg08@H
DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg
https://www.youtube.com/"

SpaceX In-Flight Abort Test"Recommended: NASA Video*
SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAo"nav"B/watch?v=mu5Ydz34oVc&feature=push-fr&attr_tag=WQZST9cYBH8yY01w%3A6"id"COvK+bnsmucCEJQB"attributionTag"WQZST9cYBH8yY01w:6{X`
hrz*
p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg08@H
DATA:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg
RESOURCES:https_www.youtube.com_0p#https://www.youtube.com/#1SpaceX In-Flight Abort TestRecommended: NASA Videohttps://lh4.googleusercontent.com/-yGgyfF0s0tA/AAAAAAAAAAI/AAAAAAAAAAA/kiuOchD_wtI/s96-mo/photo.jpg

References:

  1. sed:
  2. explains how to use regex groups () and \1 \2 \3 etc to reference those groups! - https://unix.stackexchange.com/questions/78625/using-sed-to-find-and-replace-complex-string-preferrably-with-regex/78626#78626
  3. How to use sed to find and replace text in files in Linux / Unix shell - https://www.cyberciti.biz/faq/how-to-use-sed-to-find-and-replace-text-in-files-in-linux-unix-shell/
4
  • FYI: "Final one-liner" does not work for me using PopOS-installed Chrome on Ubuntu 22.04. Even changing find ~ to sudo find / it does not find what's being searched for, and tail fails.
    – Phrogz
    Feb 21 at 16:22
  • @Phrogz, I haven't tried it in a while. I wonder if things in Chrome or Ubuntu changed. Feb 21 at 16:40
  • @Phrogz, Actually, I just ran it on Ubuntu 22.04. Still works fine, although the output is insanely ugly. What does "PopOs-installed Chrome" mean? I installed Chrome manually on Ubuntu 22.04. Feb 21 at 16:42
  • 1
    Thanks for verifying. I have Pop! OS installed (on top of Ubuntu 22.04). It has a GUI app for installing applications, the Pop Shop. I installed Chrome using this app.
    – Phrogz
    Feb 26 at 4:54
4

As it seems not possible to get a record of the notifications directly, if I had the same problem, I would cheat by using an android phone emulator, or a phone, as the user who recommended Pushbullet. But there is not only Pushbullet, there are a lof of other apps, we could discuss the android tricks to listen and record notifications, in a separate thread.

If you are a programmer, you could maybe solve your problem though a home-made extension:

https://stackoverflow.com/questions/15949606/how-can-i-listen-to-notifications

"You can hook the webkitNotifications.createNotification function so that whenever a notification is created you run some particular code."

0
3

Touching something that was mentioned a bit above but with a twist that insure you are not missing the notification on OSX:

  1. On the right side of the main top bar, click on the notification icon.

  2. Click the cogwheel (lower right of the notification display)

  3. Select Chrome to setup how notifications are displayed.

  4. By default "Banners" are selected and they can vanish automatically. Instead, select the "Alert" type and they will stay there as long as you are not acknowledging them!

You are welcome :)

3

If using MS-Windows 10. You can see the history of Push Notifications. On the very bottom right corner of your PC screen on the taskbar is what looks like a speech bubble and if you hover over it you will see it is actually called "notifications". If you click that bubble it will show your unread/new emails and any push notifications you have not dismissed. I came here looking for this answer and did not find it but then managed to work this out. I am using Windows 10.

1
  • Yes, this is a recent thing on Win10, but it is the eventual answer for Windows.
    – paradroid
    Dec 12, 2018 at 14:55
2

Thanks to Corey's answer above, and a lazy Saturday with too much time on my hands, I can now see a list of recent Chrome notifications in my IDE's console, where I can even click on the URLs.

The code is crappy and uses crude heuristics since I have no clue of the correct way to interpret the binary data.

But it's a ton better than nothing. Example output (excerpt):

https://www.finanzen.net/nachricht/aktien/kw-9-tops-und-flops-der-tecdax-aktien-in-der-vergangenen-woche-7195100
https://images.finanzen.net/mediacenter/unsortiert/TecDAX_boerse_frankfurt0016_kl.jpg
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.*
KW 9: Tops und Flops der TecDAX-Aktien in der vergangenen Woche
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.
HideOnTheseRoutes
Home/Index;Article/News/Index
tag-7195100
NotificationIdentifier
1061622960{


https://www.youtube.com/watch?v=W-mlD_bYKdU&feature=push-u-sub&attr_tag=0SL8UpnrTOnTECxr%3A6
https://lh5.googleusercontent.com/-raJM5SITO34/AAAAAAAAAAI/AAAAAAAAAAA/UtLljlL4Wpc/s96-c-mo/photo.jpg
New from Market Moves
Trade Recap: $1,500 in PROFITS*˜
COuAyJGY4uACEAY=
attributionTag
0SL8UpnrTOnTECxr:6{
 from Market MovesTrade Recap: $1,500 in PROFITS

Crucifixion-worthy Java code:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;




/**
 * v[1, 2019-03-02 13:00 UTC]
 *
 * by dreamspace-president.com
 */
final public class CrappyChromeNotificationHistoryReader {


    public static void main(final String[] args) {

        final File file = new File(
                "C:\\Users\\[YOUR_NAME_HERE]\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Platform Notifications\\000003.log");

        final List<ChromeNotificationStuff> notifications = obtainChromeNotificationStuff(file);
        for (ChromeNotificationStuff notification : notifications) {
            System.err.println();
            System.err.println(notification);
        }
        System.exit(0);
    }


    public static List<ChromeNotificationStuff> obtainChromeNotificationStuff(final File file) {

        final List<ChromeNotificationStuff> ret = new ArrayList<>();

        final List<DumbTokenList> listOfDumbTokenLists = doTheInsaneParsingThing(file);
        int instanceCounter = 0;
        for (DumbTokenList dtl : listOfDumbTokenLists) {

            final List<String> urls = new ArrayList<>();
            final List<String> texts = new ArrayList<>();

            for (String token : dtl.tokens) {
                if (token.startsWith("https://") || token.startsWith("http://")) {
                    urls.add(token);
                } else {
                    texts.add(token);
                }
            }


            // Remove unimportant URLs.
            for (int i = urls.size() - 1; i > 0; i--) {
                final String urlThis = urls.get(i);
                final int lenThis = urlThis.length();
                for (int ii = i - 1; ii >= 0; ii--) {
                    final String urlThat = urls.get(ii);
                    final int lenThat = urlThat.length();

                    if (lenThis > lenThat) {
                        if (urlThis.startsWith(urlThat)) {
                            final String removed = urls.remove(ii);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThis); // because was better or equal
                            break;
                        }
                    } else {
                        if (urlThat.startsWith(urlThis)) {
                            final String removed = urls.remove(i);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThat); // because was better or equal
                            break;
                        }
                    }

                }
            }

            ret.add(new ChromeNotificationStuff(instanceCounter, urls, texts));
            instanceCounter++;
        }

        ret.sort(null);

        return ret;
    }


    final public static class ChromeNotificationStuff implements Comparable<ChromeNotificationStuff> {


        private final int instanceCounter;
        final public List<String> urls;
        final public List<String> texts;


        private ChromeNotificationStuff(final int instanceCounter,
                                        final List<String> urls,
                                        final List<String> texts) {

            this.instanceCounter = instanceCounter;

            this.urls = Collections.unmodifiableList(urls);
            this.texts = Collections.unmodifiableList(texts);
        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String url : urls) {
                sb.append(url).append('\n');
            }
            for (String text : texts) {
                sb.append(text).append('\n');
            }
            return sb.toString();
        }


        @Override
        public int compareTo(final ChromeNotificationStuff o) { // Newest (= last) notifications first, please.

            return Integer.compare(o.instanceCounter, instanceCounter);
        }
    }




    final private static double MIN_LENGTH_DIFFERENCE_RATIO = 0.7;//0.9;
    final private static double MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES = 0.2;




    final private static class DumbTokenList {


        final private static int MIN_LENGTH = 10; //6;
        final private static String[] EXTENSIONS = new String[] { ".jpg", ".jpeg", ".png", ".gif", ".html", ".htm", ".php" };
        final private static int MAX_EXTRA_CRAP_AFTER_EXTENSIONS = 3;
        final private static String SAFE_URL_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;="; // https://stackoverflow.com/a/1547940/3500521

        final private String originalText;
        final private List<String> tokens;


        private DumbTokenList(final String textWithBinaryCrap) {

            originalText = textWithBinaryCrap;

            final List<String> tokens = new ArrayList<>();

            final Consumer<String> addTokenButTryToDecrappifyExtensionsFirstAnTing = token -> {


                if (token.startsWith("ttps://") || token.startsWith("ttp://")) {
                    token = "h" + token;
                }


                final List<String> newTokens = new ArrayList<>();

                if (token.startsWith("http")) {
                    final int tokenLength = token.length();
                    boolean found = false;
                    for (int i = 0; i < tokenLength; i++) {
                        final char c = token.charAt(i);
                        if (SAFE_URL_CHARACTERS.indexOf(c) < 0) {
                            newTokens.add(token.substring(0, i));
                            newTokens.add(token.substring(i));
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        newTokens.add(token);
                    }
                } else {
                    newTokens.add(token);
                }

                for (String newToken : newTokens) {


                    String foundExt = null;
                    int foundExtLen = 0;
                    int foundExtAt = -1;
                    for (String extension : EXTENSIONS) {
                        final int idx = newToken.indexOf(extension);
                        if (idx >= 0) {
                            final int extLen = extension.length();
                            if (idx > foundExtAt || (idx == foundExtAt && extLen > foundExtLen)) {
                                foundExt = extension;
                                foundExtLen = extLen;
                                foundExtAt = idx;
                            }
                        }
                    }
                    if (foundExt != null) {
                        final int amountOfCharactersAfterThisFind = newToken.length() - foundExtAt - foundExtLen;
                        if (amountOfCharactersAfterThisFind <= MAX_EXTRA_CRAP_AFTER_EXTENSIONS) {
                            // OK. Shorten this bitch.
                            newToken = newToken.substring(0, foundExtAt + foundExtLen);
                        }
                    }


                    if (newToken.startsWith("http")) {
                        if (!newToken.startsWith("http://") && !newToken.startsWith("https://")) {
                            continue;
                        }
                    }


                    if (newToken.startsWith("/watch?v=")) {
                        newToken = "https://www.youtube.com" + newToken;
                    }


                    if (newToken.length() >= MIN_LENGTH) {
                        tokens.add(newToken);
                    }


                }

            };

            final StringBuilder sb = new StringBuilder();

            final int len = textWithBinaryCrap.length();
            for (int i = 0; i <= len + 1; i++) {

                final char c = i < len ? textWithBinaryCrap.charAt(i) : 0;

                if (c < ' ' || c == '"') {

                    String potentialText = sb.toString();
                    while (true) {
                        final int httpIDX = potentialText.indexOf("http", 1);
                        if (httpIDX < 0) {
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(potentialText);
                            break;
                        } else {
                            final String snippet = potentialText.substring(0, httpIDX);
                            potentialText = potentialText.substring(httpIDX);
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(snippet);
                        }
                    }

                    sb.setLength(0);

                    if (c == '"') {
                        // Skip this and the next. (thus "i < len +1")
                        i++;
                    }
                } else {
                    sb.append(c);
                }
            }


            // Remove quasi-duplicates. Sue me.
            //            System.err.println("\n*** STARTING DEDUPLICATION ***");
            final int lSize = tokens.size();
            for (int i = lSize - 1; i > 0; i--) { // (not 0 itself, wouldn't make sense)

                if (i < tokens.size()) {

                    final String entry = tokens.get(i);

                    for (int ii = i - 1; ii >= 0; ii--) { // (incl. 0)

                        final String otherEntry = tokens.get(ii);

                        final Boolean removeNoneOrFirstOrSecond = areLinesTooSimilar(entry, otherEntry);
                        if (removeNoneOrFirstOrSecond != null) {

                            if (!removeNoneOrFirstOrSecond) {
                                final String removed = tokens.remove(i);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + otherEntry); // because was better or equal
                            } else {
                                final String removed = tokens.remove(ii);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + entry); // because was better or equal
                            }
                            break; // IMPORTANT!
                        }

                    }
                }
            }


            this.tokens = Collections.unmodifiableList(tokens);

        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String token : tokens) {
                sb.append(token).append('\n');
            }
            return sb.toString();
        }


    }


    /**
     * Do NOT call with NULL/EMPTY arguments.
     *
     * @return NULL if not too similar. False if the FIRST seems superfluous. True if the SECOND seems superfluous.
     */
    private static Boolean areLinesTooSimilar(final String line1,
                                              final String line2) {

        final int l1 = line1.length();
        final int l2 = line2.length();

        final double lenDiffRatio = Math.min(l1, l2) / (double) Math.max(l1, l2); // Results in 1 or less.

        if (lenDiffRatio >= MIN_LENGTH_DIFFERENCE_RATIO) {

            if (l2 < l1) {
                // Compare the other way round.
                if (line1.contains(line2)) {
                    return false;
                }
            } else {
                if (line2.contains(line1)) {
                    return true;
                }
            }

        }

        return null;
    }


    private static List<DumbTokenList> doTheInsaneParsingThing(final File file) {

        final List<DumbTokenList> ret = new ArrayList<>();

        final StringBuilder sb = new StringBuilder();
        try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {

            final int bufMinus1 = 4;
            final Charset charset = Charset.forName("Cp1252"); // =ansi

            final int[] buf = new int[bufMinus1 + 1]; // "DATA"
            //            while ((buf[buf.length - 1] = is.read()) >= 0) {
            while (true) {

                buf[bufMinus1] = is.read();

                if (buf[bufMinus1] < 0 || (
                        buf[0] == 'D' &&
                                buf[1] == 'A' &&
                                buf[2] == 'T' &&
                                buf[3] == 'A' &&
                                buf[4] == ':')) {

                    if (sb.length() > 0) {
                        ret.add(new DumbTokenList(sb.toString()));
                        sb.setLength(0);
                    }

                    if (buf[bufMinus1] < 0) {
                        break;
                    }

                } else {

                    sb.append(new String(new byte[] { (byte) buf[bufMinus1] }, charset));
                    //                    sb.append((char) buf[bufMinus1]);
                }


                // Shift minibuffer to front.
                for (int i = 0; i < bufMinus1; i++) {
                    buf[i] = buf[i + 1];
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }


        // DEDUPLICATE DTLs
        for (int i = ret.size() - 1; i > 0; i--) {

            if (i < ret.size()) {
                final DumbTokenList dtlThis = ret.get(i);
                final int dtlThisTokenCount = dtlThis.tokens.size();

                for (int ii = i - 1; ii >= 0; ii--) {
                    final DumbTokenList dtlThat = ret.get(ii);
                    final int dtlThatTokenCount = dtlThat.tokens.size();


                    int scoreViaRemainingLines_this = dtlThisTokenCount;
                    int scoreViaRemainingLines_that = dtlThatTokenCount;


                    for (int o = 0; o < dtlThisTokenCount; o++) {
                        final String tokenThis = dtlThis.tokens.get(o);
                        for (int oo = 0; oo < dtlThatTokenCount; oo++) {
                            final String tokenThat = dtlThat.tokens.get(oo);

                            final Boolean tooSimilar = areLinesTooSimilar(tokenThis, tokenThat);
                            if (tooSimilar != null) {
                                scoreViaRemainingLines_this--;
                                scoreViaRemainingLines_that--;
                                break;
                            }

                        }
                    }

                    if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) {
                        throw new Error();
                    }

                    final double scoreActual_this = scoreViaRemainingLines_this / (double) dtlThisTokenCount;
                    final double scoreActual_that = scoreViaRemainingLines_that / (double) dtlThatTokenCount;


                    if (scoreViaRemainingLines_this < scoreViaRemainingLines_that) {
                        if (scoreActual_this < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(i);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThat);
                            break; // IMPORTANT.
                        }
                    } else {
                        if (scoreActual_that < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(ii);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThis);
                            break; // IMPORTANT.
                        }
                    }


                }

            }
        }

        return ret;
    }


}
2
  • 1
    To get this running, I used the following commands, javac "C:\Users\MLM\Downloads\CrappyChromeNotificationHistoryReader.java"(to compile), java -cp C:\Users\MLM\Downloads CrappyChromeNotificationHistoryReader(to run) The script was failing at if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) { so I commented out all parsing in doTheInsaneParsingThing and just printed out everything System.out.println(sb.toString()); when the token gets added to the list. It looks like "Platform Notifications" only handles the server worker push notifications.
    – MLM
    Jun 30, 2019 at 2:46
  • @MLM: Thanks for the javac info. As for the problem: Works for me if I paste the source into an open Java 8 IntelliJ project, put in my user name ("file" variable), and run the code. Jun 30, 2019 at 9:56
1

There is a Chrome extension called NOTYFY which aggregates notifications from many sites that you are logged into (gmail, facebook, stackoverflow, twitter, etc).

NOTYFY essentially builds a running log of notifications from these sites so you can access them in one place.

So the answer is yes, you can access notification history but in a very constrained way.

NOTYFY does not aggregate all site notifications, just the ones it is programmed for and are logged in. Even those require patches as the sites change their notification APIs.

enter image description here

-2

Seems as though Pushbullet may solve your issue. They claim you can see your missed notifications using their Chrome extension.

https://blog.pushbullet.com/2014/10/23/easily-access-your-recent-notifications-in-chrome/

7
  • Please read How to recommend software for minimum required information and suggestions on how to recommend software on Super User. To keep your answer useful even if the provided link(s) breaks these details should be edited into your answer. Sep 9, 2016 at 1:30
  • Hey, nice. I'll try that out. I actually already use Pushbullet, but was unaware of this Chrome extension.
    – paradroid
    Sep 12, 2016 at 0:32
  • Can't seem to find this feature. A notification popped and there's not trace of it in the notification's history.
    – madprops
    Sep 14, 2016 at 2:44
  • I rethought the question and the catch is this. If your phone gets a notification, pushbullet will deliver it to your desktop and let you know you have possibly unread notifications (you may have seen it on your phone or what have you). What sites are you getting chrome notifications for? If there's an app for it, you can always install it and you'll then get the notifications from pushbullet to your desktop/laptop/whatever. Sep 15, 2016 at 12:40
  • 2
    The "Notifications" feature in Pushbullet is only for seeing notifications from your Android phone on the desktop, and the same with iPhone if you have a Mac desktop. It has nothing to do with Chrome notifications.
    – Boaz
    Nov 27, 2016 at 8:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .