DEV Community

Cover image for How I Added an "Order on WhatsApp" Button to a Café Website with Plain JavaScript
Abinesh AH
Abinesh AH

Posted on AI-assisted

How I Added an "Order on WhatsApp" Button to a Café Website with Plain JavaScript

A lot of small cafés and food shops in India take orders on WhatsApp. Customers message "2 samosa, 1 filter coffee", the owner adds it up, replies with the total, and that's the whole system.

So when I rebuilt a café website, I didn't want a payment gateway or a backend. I wanted the cart to turn into a neat WhatsApp message that lands in the shop owner's chat, already totalled.

It turned out to need about 15 lines of JavaScript. Here's how it works.

The trick: WhatsApp's "click to chat" link

WhatsApp has an official link format that opens a chat with any number:

https://wa.me/<phone>?text=<message>
Enter fullscreen mode Exit fullscreen mode
  • <phone> is the full number with country code, digits only: no +, spaces or dashes. For India: 919876543210.
  • text is optional. Whatever you put there appears pre-typed in the message box.

Try it in your browser (with your own number):

https://wa.me/919876543210?text=Hello%20from%20my%20website
Enter fullscreen mode Exit fullscreen mode

On a phone it opens the WhatsApp app. On a laptop it offers WhatsApp Web or the desktop app. No API key, no sign-up, no cost.

One important detail: the message is never sent automatically. WhatsApp only fills the box, and the person still taps Send. That's a good thing, because websites can't send messages on anyone's behalf.

Step 1: Keep the cart simple

The cart is just an array of item ids and quantities. The menu data lives in a separate array:

const MENU = [
  { id: 'samosa', name: 'Samosa', price: 30 },
  { id: 'filter-coffee', name: 'Filter Coffee', price: 80 },
  // ...
];

let cart = [
  { id: 'samosa', qty: 2 },
  { id: 'filter-coffee', qty: 1 },
];

const findMenuItem = (id) => MENU.find((item) => item.id === id);
Enter fullscreen mode Exit fullscreen mode

Step 2: Turn the cart into a message

const formatPrice = (amount) => `₹${amount.toLocaleString('en-IN')}`;

function getCartTotal() {
  return cart.reduce((sum, entry) => sum + findMenuItem(entry.id).price * entry.qty, 0);
}

function buildOrderMessage() {
  const lines = cart.map((entry) => {
    const item = findMenuItem(entry.id);
    return `${entry.qty} x ${item.name} - ${formatPrice(item.price * entry.qty)}`;
  });
  return `Hello! I'd like to order:\n${lines.join('\n')}\nTotal: ${formatPrice(getCartTotal())}`;
}
Enter fullscreen mode Exit fullscreen mode

For the cart above, this produces:

Hello! I'd like to order:
2 x Samosa - ₹60
1 x Filter Coffee - ₹80
Total: ₹140
Enter fullscreen mode Exit fullscreen mode

Step 3: Encode it and open WhatsApp

A URL can't contain spaces, new lines or symbols like ₹ directly. encodeURIComponent() converts them into safe codes (a space becomes %20, a new line %0A):

const WHATSAPP_NUMBER = '919876543210'; // the shop's number

checkoutButton.addEventListener('click', () => {
  if (cart.length === 0) return;
  const url = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(buildOrderMessage())}`;
  window.open(url, '_blank', 'noopener');
});
Enter fullscreen mode Exit fullscreen mode

window.open(..., '_blank') opens WhatsApp in a new tab, so the café website stays open behind it.

And this is what the shop owner receives:

WhatsApp order message

One UX problem I didn't expect

After testing it, I noticed something: when you come back to the website, the cart is still full. The page has no way to know whether you actually pressed Send in WhatsApp, because WhatsApp doesn't report anything back.

Clearing the cart automatically felt wrong (if someone closes WhatsApp without sending, their order is gone). So instead, after opening WhatsApp the cart shows a message and a small button:

cartMessage.textContent = 'WhatsApp opened in a new tab. Send the message there to confirm your order.';
newOrderButton.hidden = false; // "Order sent? Start a new order"
Enter fullscreen mode Exit fullscreen mode

The customer clears the cart themselves once they've sent it. It's a small thing, but it removed the "did my order go through?" confusion.

What this approach can't do

It's worth being honest about the limits:

  • No online payment. The shop confirms the order and collects payment (UPI, cash) in the chat.
  • No order database. Orders only exist as WhatsApp messages.
  • The shop's number is visible in the page source. That's fine for a business number, not for a private one.

For a small café, those are acceptable trade-offs for something that's free and needs zero backend.

Try it

You can play with the full version here (the demo checkout shows a thank-you message instead of opening WhatsApp, so nobody spams a real number): https://ahcoffeeshop.netlify.app

Café website cart

It's plain HTML, CSS and JavaScript: a filterable menu built from one data file, a cart saved in localStorage, the WhatsApp checkout, and a mobile layout.

I also packaged it as a ready-to-use template with a setup guide, for anyone who wants to skip building it from scratch: Coffee Shop & Café Website Template. (Full disclosure: that's my own product.)

If you've built something similar, or have ideas to improve the WhatsApp flow, I'd love to hear about it in the comments. 👋

Top comments (0)