DEV Community

Cover image for Ultrasonic payments
Charlie Gerard for Stripe

Posted on • Originally published at charliegerard.dev

Ultrasonic payments

Recently, my colleague Mike Bifulco wrote a blog post about using Near-Field Communication (NFC) technology to request payment using NFC tags and Stripe Payment Links. In a similar spirit, I came across the concept of “Ultrasonic payments”, a technology based on transferring data through inaudible sounds, and decided to experiment and look into how to implement such a payment method with Stripe.

Here’s the result below. My iPad is in airplane mode, so not connected to the internet, and transmits a payment link to my phone via ultrasound.

If you would like to try this out, check out the live demo or have a look at the repository on GitHub.

Disclaimer: This is an experiment. The ultimate goal would have been to implement a solution similar to tap-to-pay using ultrasounds, however, even though this is possible and has been done by companies such as LISNR, this is not something that can be easily prototyped. Instead, I decided to explore by sending Payment Links, a no-code payment solution that allows you to request payment from customers with a simple link. I still wanted to share what I tried and learned, as this technology can still be applied to different applications than payments.

Soundwaves

Before focusing on payments, it’s important to understand how devices transform analog sound into digital data so, without going into too much detail, here’s a brief explanation of how it works.

Sound is created by vibrations that produce shifts in the flow of molecules. These molecules bump into each other, creating a chain reaction called a sound wave. When this wave reaches a microphone, the movement of air molecules creates pressure against the thin membrane found in the device, creating electrical signals that are then converted to digital values using an Analog to Digital converter (ADC).

Animation showing how sound waves create pressure against the membrane of a microphone, creating electrical energy.
Source: "How do microphones work?"

Humans can usually hear sounds from a frequency range of 20Hz-20kHz. However, it doesn’t mean that sound does not exist outside of these frequencies, it only means we cannot hear it. As a result, you can transmit data at frequencies outside of what the human ear can detect, through inaudible sounds. This is a technique called ultrasonic data transmission.

Graphic representing the electromagnetic spectrum where the spectrum of frequencies humans can hear falls between infrasound and ultrasound
Source: What is ultrasound?

So, how can we use this to transmit a payment?

Ultrasonic data transmission in JavaScript

This prototype is going to rely on quiet.js, a JavaScript library to transmit data using sound.

The same way that usual tap-to-pay systems require both the terminal and personal device to be NFC-enabled, sending data through sound requires the devices involved to have a microphone and speaker.

For the purpose of this experiment, the merchant’s device should have a speaker as it will be transmitting the payment link, and the customer’s device should have a microphone to receive it.
This scenario would allow merchants to use an iPad in-store to sell their products, without having to acquire a terminal device.

Transmitting data

Using quiet.js to transmit text via sound can be done by creating a transmitter instance, specifying some parameters including the frequency, gain and frame length, and finally calling the .transmit() method with the payload.

Let’s look into the code needed to do this.

Initial setup

To start, the library needs to be imported. Quiet.js includes a blob of libquiet that it relies on, and JavaScript bindings, so in my prototype, I used script tags to import quiet.js and quiet-emscripten.js. I also initiated Quiet with the path to a couple of required files; profilesPrefix indicates where the quiet-profiles.json file is located and memoryInitializerPrefix, indicates where quiet-emscripten.js.mem can be found.

<script type="text/javascript" src="quiet.js"></script>
<script>
  Quiet.init({
    profilesPrefix: "/",
    memoryInitializerPrefix: "/"
   });
</script>
<script
  async
  type="text/javascript"
  src="quiet-emscripten.js"
></script>
Enter fullscreen mode Exit fullscreen mode

Creating a transmitter

To create a transmitter, there is a transmitter() method where you need to indicate which profile you’d like to use, as well as a callback function that is called when the transmission has ended.

var transmit = Quiet.transmitter({
  profile: profilename,
  onFinish: onFinish
});
Enter fullscreen mode Exit fullscreen mode

The profile is the set of parameters I mentioned previously, containing information about how the data should be transmitted (the frame length, gain, etc.).

The one I used looks like this:

 "ultrasonic": {
   "mod_scheme": "gmsk",
   "checksum_scheme": "crc32",
   "inner_fec_scheme": "v27",
   "outer_fec_scheme": "none",
   "frame_length": 34,
   "modulation": {
     "center_frequency": 19000,
     "gain": 0.15
   },
   "interpolation": {
     "shape": "rrcos",
     "samples_per_symbol": 14,
     "symbol_delay": 4,
     "excess_bandwidth": 0.35
   },
   "encoder_filters": {
     "dc_filter_alpha": 0.01
   },
   "resampler": {
     "delay": 13,
     "bandwidth": 0.45,
     "attenuation": 60,
     "filter_bank_size": 64
   }
 },
Enter fullscreen mode Exit fullscreen mode

No need to dive into what all these properties do right now, they mainly indicate how the data should be encoded.

Next, a data string can be transmitted using the transmit() method and passing a value converted to an array buffer. For this prototype, I’m sending a payment link.

transmit.transmit(Quiet.str2ab(https://buy.stripe.com/test_00gfZ73t04dxaGI3cc”));
Enter fullscreen mode Exit fullscreen mode

Creating a receiver

Creating a receiver is similar to creating a transmitter. First you need to use the receiver() method, passing the profile and some callback functions, and then decode the data received.

 Quiet.receiver({
   profile: profilename,
   onReceive: onReceive
 });
Enter fullscreen mode Exit fullscreen mode

The onReceive() function receives a payload, converts the array buffer in UTF8 to string, creates a URL object and checks if the host is “buy.stripe.com” to ensure the link sent is a payment link. If so, it opens it in the browser window.

const onReceive = (recvPayload) => {
 const link = Quiet.ab2str(recvPayload);
 const linkURL = new URL(link);

 if (linkURL.host === "buy.stripe.com") {
   window.location.href = linkURL;
 }
};
Enter fullscreen mode Exit fullscreen mode

More code would be needed to implement error handling or working with more complex data structures but for the purpose of this experiment, that’s pretty much it!

Learnings

Before starting this experiment, I asked myself a few questions I wanted to be able to answer.

Will it work in a noisy environment?

I tested this while playing music in the background and the receiver still detected the payment link with no problem. Considering that the music was playing at a different frequency, it makes sense.

Will it work if the transmitter is playing music at the same time?

Yes. I tested this with my laptop as the transmitter. While playing a video, it still successfully transmitted the payment link.

How far can the data be transmitted?

In this experiment, it successfully transmitted the payment link up to 55cm (21.65 inches) away from the transmitter (yes, I measured). However, the further away the receiver was from the transmitter, the more failed attempts there were.

How much data can be transmitted?

I did not experiment too much in that sense, but according to their official demo, it is possible to transmit images using quiet.js.

Why experiment with this?

With the growth in adoption of contactless payments, I wanted to look into alternatives to NFC technology. The COVID-19 pandemic made people more concerned about touching surfaces, including in stores, and even though NFC is contactless, the distance between a merchant's terminal and a customer’s phone or card is quite small. NFC technology enables communication between two electronic devices over a distance of 4 cm (1.5 inches) or less. Ultrasonic payment solutions would enable communication over a greater distance.

Moreover, this technology transmitting data through sounds also means that it does not require the devices to be connected to the internet, potentially making this more secure. To process payments, a connection would end up being needed but there could be other opportunities than payments where it would be a valid solution.

Considering that this technology only uses a microphone and speaker, it could allow more devices to become payment terminals, such as laptops, TVs, etc.

Conclusion

This technology isn’t new, and can be used for more purposes than payments. Advertising companies have used this technology to send out inaudible marketing beacons from TV ads to nearby phones running specific applications for targeted advertising for years (yikes). Google has also implemented this technology in some of their products to automatically detect nearby devices. When it comes to payments, while there are more regulations and security concerns to take into consideration, it is still interesting to explore this space, and understand its opportunities and limitations.

What would you do with this technology? Feel free to clone the repo and let us know what you build!

📣 Follow @StripeDev and our team on Twitter
📺 Subscribe to our Youtube channel
💬 Join the official Discord server
📧 Sign up for the Dev Digest

About the author

Charlie's profile picture

Charlie Gerard is a Developer Advocate at Stripe, a creative technologist and Google Developer Expert. She loves researching and experimenting with technologies. When she’s not coding, she enjoys spending time outdoors, trying new beers and reading.

Discussion (8)

Collapse
rouilj profile image
John P. Rouillard

Neat idea. What about eavesdropping on the signal? IIUC that's one of the reasons NFC has such a short range.

You noted that 21-22 inches allows reliable reception. Would it be possible by changing volume/frequency/encoding to tune the reliable reception range down to say 10-12 inches and make it difficult to receive (< 99% chance of reception) your signal by the person behind you in the checkout line (post covid, so they aren't 6 feet away from you 8-).

You mention being able to transmit images. Is the data rate high enough that it could be used to replace bluetooth for sending a business card or resume? Also I assume it can be used for broadcast. I was thinking of sharing a business card to 3 or 4 people at the same time.

Thanks for the writeup.

Collapse
swp profile image
Scott Palmer

"Moreover, this technology transmitting data through sounds also means that it does not require the devices to be connected to the internet, potentially making this more secure."

NFC uses electromagnetic waves instead of 'mechanical' sound waves. Neither has anything to do with being connected to the internet.

Collapse
leob profile image
leob • Edited on

Spot on, it's just data transmission - a different implementation of the "physical layer" in the OSI model. In an ideal world this would have nothing to do with a payment method (well in fact the author says as much), it would just be a matter of swapping the "transport layer" by loading a different 'driver' so to speak.

It sounds like a nice new gimmick, but yeah that's about it.

Collapse
cassidoo profile image
Cassidy Williams

This is so cool, I'm astounded

Collapse
spiritbro1 profile image
spiritbro1

super cool but we still need to connect to internet right? to finish payment?

Collapse
maxfindel profile image
Max F. Findel

This is a great working demo! I'm glad you went all the way to implement it, even using Stripe colors and all 😊

Collapse
desouzafelipe profile image
desouzafelipe

Liked. Very useful to exchange data offline between devices from different technologies. It is so cyberpunk! Cool!

Collapse
digoriepiper profile image
Capt. Digorie Piper

That's quite a distance for eavesdropping or masquerading. How do you prevent a nearby device sending out a misdirected payment link ?