QR Code API for developers

The QRotto JavaScript API makes the same codes as this site, from your own code. It runs in your browser or on your server: there is no key, no rate limit, no account, and nothing is sent to QRotto.

Try it

Quick start in the browser

Load the encoder and the API, then ask for an SVG. The second call shows the print check every QRotto code gets.

<div id="code"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js"></script>
<script src="https://qrotto.com/qrotto-qr.js"></script>
<script>
  document.getElementById("code").innerHTML = QRotto.svg("https://example.com/menu", { size: 512 });

  const check = QRotto.make("https://example.com/menu");
  console.log(check.modules, check.minPrintMm + " mm");   // 25 20 mm
</script>

Node.js: a batch of files

The same file works on a server. This script writes an SVG and a PNG for each table, which suits print runs and label systems.

// npm install qrcode-generator   and save qrotto-qr.js next to this file
const fs = require("fs");
const QRotto = require("./qrotto-qr.js");

const tables = ["T1", "T2", "T3"];
for (const t of tables) {
  const link = "https://example.com/menu?table=" + t;
  fs.writeFileSync(`table-${t}.svg`, QRotto.svg(link));            // sharp at any size
  fs.writeFileSync(`table-${t}.png`, QRotto.png(link, { size: 1200 })); // no other dependency
  console.log(t, QRotto.make(link).minPrintMm + " mm minimum");
}

Functions

FunctionWhat you get
QRotto.make(text, options)The code as data: modules (grid size), matrix (rows of true and false), minPrintMm, minPrintIn and check (ready, test-one-copy or dense).
QRotto.svg(text, options)An SVG string: one path, quiet zone included. Best for print and for files.
QRotto.canvas(text, options)Browser only. A canvas element you can show, print or save.
QRotto.pngDataUrl(text, options)Browser only. A PNG as a data URL, ready for an img or a download link.
QRotto.png(text, options)Node.js only. PNG file contents as a Buffer, with no other dependency.
QRotto.payload.*The text phones expect for WiFi, contact cards, email, SMS, calls, WhatsApp, places and events, built with the same rules as the tools on this site. A mistake that would print a broken code, like a WhatsApp number without its country code, stops with a clear error instead.

Options

OptionMeaning
ecError correction: L, M, Q or H. Default M. Use H when a logo covers part of the code.
marginQuiet zone in modules. Default 4, the standard. Below 4 some phones struggle.
sizeWidth in pixels for PNG and canvas, and the width and height attributes of the SVG. Default 1024.
dark, lightColours as #rrggbb. Defaults black on white. Light can be transparent; keep dark modules on a light background.
titleSVG only. A title for screen readers, such as "Menu for table 4".

Payloads: the right text for each kind of code

Most broken codes are not broken images but wrong text inside them: a WiFi password with an unescaped semicolon, a WhatsApp number with a leading zero. The payload helpers build the format phones expect.

QRotto.payload.wifi({ ssid: "Cafe;Guest", password: "p:w1", security: "WPA" })
// WIFI:T:WPA;S:Cafe\;Guest;P:p\:w1;;

QRotto.payload.vcard({ name: "Sara Khan", phone: "+92 300 1234567", email: "sara@example.com", org: "Corner Cafe" })
QRotto.payload.whatsapp({ number: "+92 300 1234567", message: "Hi, a table for two" })
QRotto.payload.whatsapp({ number: "0300 1234567" })
// Error: drop the 0 at the start and put the country code first

QRotto.payload.email({ to: "hello@example.com", subject: "Booking" })
QRotto.payload.sms({ number: "+1 555 0100", message: "STOP" })
QRotto.payload.phone("+1 555 0100")
QRotto.payload.geo({ lat: 31.588, lng: 74.31 })
QRotto.payload.event({ title: "Open day", start: "2026-12-05T10:00:00Z", location: "Main hall" })

make() returns the smallest safe print width: 0.4 mm per module including the quiet zone, and never below 20 mm. A short link needs 20 mm; a full contact card with a job title, email and website (about 240 characters) needs about 28 mm. Print one copy at that size and scan it before a full run.

Empty text, or more than one code can hold (about 2,300 bytes at the default error correction), stops with an Error that says what to change, so a batch job never writes a blank or broken file.

Why it runs on your side

Is there a hosted REST API?

Not yet. A hosted endpoint would mean sending your data to a server and sharing limits with other users, which is exactly what this API avoids. If your team needs one, write to hello@qrotto.com and tell us how you would use it.

Licence and versions

Version 1.0.0, MIT licence: use it in commercial work, copy it, change it. You can load it from qrotto.com as above, or save qrotto-qr.js and serve it from your own site. Tested with qrcode-generator 1.4.4 in browsers and 2.0.4 on Node.js, decoding every code it makes. It builds on qrcode-generator by Kazuhiko Arase, also MIT. Using WordPress? The QRotto plugin does the same inside your site.