store store cards

Visit project ⬀

store store cards is a website that allows you to store loyalty or membership cards to your device (usually a mobile phone).

These cards have barcodes or QR codes of some sort which represent your membership number. You can use your device's camera to scan the barcode and create a 'virtual' card quickly.

Please note: this is not a wallet app, and it does not deal with financial information of any kind.

image of phone screen showing a card barcode being rendered, it says coco's cafe

You can "install" the website to your device, in which case it effectively acts like an app, or what is also known as a Progressive Web App.

Once installed, it should work offline. That is, you don't need any data service to access the cards you stored. This allows you to use the website even when there's no mobile reception and the shop doesn't offer free wifi. For example, when you reach the till of the grocery shop in the basement of the department store. Also, since store store cards does not try to find your location to recommend you "offers", it is as private and fast as it can be, and it won't make you waste your precious battery charge or time when it you're trying to scan the card and a queue of people is forming behind you...

Oh, and it is also really small (compared to a native app): the final code is less than 2 megabytes (yes, mega bytes).

Privacy

This works entirely client side. The data stays in your device. I do not know what you scan, and I do not want to know!

If you want to make a copy of your cards or want to see what is stored, inspect the website with your favourite developer tools, and look in localStorage.

I run lightweight statistics to get a sense of how many people use the website, and detect crashes or bugs. Individual visitors aren't identifiable, as I don't store any personal user data, only the fact that you visited, the type of operating system you use, etc (this is information that you provide already by browsing the internet). If your device has any sort of tracker-blocking functionality, it is likely to block my statistics code, so if the app exhibits bugs when you visit I will never know, and it's OK.

The statistics service is hosted in Europe. The data is not made available to anyone. There are no ads or any other third-party script delivered with this website.

How to install or add to your home screen

This depends on the operating system and browser you're using.

iOS

Visit the website in your iOS device, then select "Share", then scroll down to "Add to Home Screen".

Android and other non-iOS

I don't know! I don't have access to recent Android or non iOS devices. But if you figure that out, please let me know and I can update this page. Thank you 💝

How to share this app with friends and family

Send them the URL: https://storestorecards.apps.5013.es/

Help! Something does not work

My camera is broken or I don't want to / can't use it

You can enter card details by hand.

The card won't scan, I can't add it to my app!

We have tested this with UK and Spanish cards. I don't know what type of obscure configurations manifest in other countries.

You can try adding the number by hand, and playing with the different barcode types, until you get something that resembles the original card.

The scanned card looks different from the physical card

Some cards only show a subset of numbers vs what the barcode actually contains. In that case, it tends to be that the first digits are not shown in the card, but the last digits are, and tend to coincide with "your membership number".

I don't really know why—I suppose to make it easier for cashiers that have to visually verify or enter card numbers with their naked eye. If you're unsure, bring both cards with you (the 'virtual' and the physical) so you can have a backup option. Once you verify that the virtual card works, you can stop carrying the physical card with you.

Some retailers will give you a big card and "portable" cards that you can add to your keyring. I've seen they sometimes differ only by a digit, but the last x digits, which are displayed on the card, are the same. My hunch is they do it to track which format is more popular, but I haven't investigated any further.

There are no icons, logotypes or colour customisation per card

This is by design. I wanted a simple app. I don't need those.

Something else doesn't work

I only have access to not very old but not very new iOS devices. I have tested this in various computers and operating systems (macOS and Linux) and it simply worked, but who knows!

If you genuinely want to help and have an idea of what is wrong, get in touch.

If you're unhappy and want to rant, maybe just find another app or service instead—I have no time or energy to help you debug weird configurations for free. No bad blood here! You're free to use whatever you want.

Why?

Libraries, coffee shops, museums, supermarkets, grocery stores, you name it: they have membership programmes, that you prove you belong to by scanning a card when you enter (or when you leave, in the case of a store).

I was tired of carrying lots of loyalty and membership cards in my wallet, so I started using an app that allowed me to scan the cards and have a "virtual" version of the card instead.

This was convenient, but the rest was really tiresome: it wanted me to give it all sorts of permissions; it often failed to render a card that would be successfully scanned... and on top of that, it was releasing almost weekly 155+ megabyte updates for no good reason, other than "Bug fixes and feature improvements". But nothing ever seemed to change or improve!

When the app we were using "warned" my partner that it would stop working unless it were updated to the latest version, I decided that we had had enough, and I set on the task of building an alternative that would be considerate with their users, and also nimbler and much faster to use. Thus, it is my gift to both of us, and now my gift for you too! 💝🎁

As of today we both use this almost daily, often several times in a row.

It has never crashed or stalled. We find it is much faster to scan, even with some barcode scanners which are quite temperamental, thanks to our secret trick: making the barcode as big as possible (actually, this is the same trick that LiDL use to speed up checkouts!).

Technology

Since this is a website, it is built using browser technologies: HTML, CSS and JavaScript. The camera is accessed using MediaDevices.getUserMedia, as I also do in a few of my other projects already.

In addition, I am using a few libraries to plug-in gaps in implementation or just to keep my sanity:

  • The Barcode Detection API, if available, or a polyfill in browsers that do not implement the API yet
  • BWIP to render the barcodes
  • Vite for handling the build, packaging, etc, with some plug-ins:
    • vite-plugin-pwa to help providing offlining and PWA functionalities
    • vite-plugin-favicons for handling the myriad versions of icons you have to provide in order to have ONE icon placed in the user's home screen 😂

I'm extremely grateful for those libraries!

The underneath libraries and polyfills support more barcode formats than the Barcode Detection API does, but in the interest of future compatibility I have decided to only expose the same formats as the real Web API would expose. These are listed here: supported barcode formats.

I have optimised the way the libraries are delivered to the users, by deliberately splitting code into dependency vs non dependency chunks. That way you only have to download what has changed, which is normally just my code, not libraries. This is a matter of kilobytes, so "app updates" are almost seamless: you access the app, close it and reopen it and you get a new version. This is much more considerate than native apps that will ship the whole list of dependencies over and over to users, without any respect for their time or bandwidth.

Some things I wish were possible

Although I'm very satisfied that the same code base works everywhere, regardless of the operating system or browser flavour, I find the following aspects frustrating. They put websites at a disadvantage compared to native apps:

  • I can't control the brightness of the screen. This would help ensure that the barcode scans even if the user has very low brightness in their device, by temporarily increasing it (and thus, increasing the contrast between black and white in the barcodes). But there's no such API for the web. We had something like that in Firefox OS, but...
  • It would also be nice to be able to control the focusing of the camera somehow. E.g. if I could for example set it to "macro" it would focus on closer distance objects, and make scanning faster. But it seems like the barcode API (and the polyfill) do a good job of detecting shapes even when slightly blurry, so not a big deal.
  • I also don't seem to be able to allow camera permissions forever with iOS. It seems to ask periodically if I want to allow camera usage, even if the app is installed. I don't know if I'm missing something in the manifest. It is mildly irritating, but I can live with it.
  • Finally, if you store some cards locally, while accessing the website through the browser, and then "install" the website as an app, you have to re-add the cards, as there's no way to have access to the same 'storage area'. This makes it harder to 'try before you buy', which would be a great advantage of websites vs native apps.

Is my phone screen cracked?

It is actually the screen protector that is cracked!

My phone fell off my hands the very same week that I bought it, as it was bigger than my previous phone, and I still hadn't developed the "grip" to hold it safely in place. We had just finished a run on a hot and humid July morning, I wanted to document the triumphal moment, and my sweaty hands just lost it...

It then landed, of all the places, on a particularly pointy piece of gravel, which chipped the edge of the screen protector, and created a long thin crack along the protector. The screen is fine, no pixels were harmed.

I often don't even notice the crack anymore—except now that I took these pictures!