Connect your QR codes to the tools you use
Leads into a spreadsheet. A message in Slack when a code gets popular. An alert on your phone when a page stops working. Pick a recipe, follow the steps, and it runs by itself.
- 1
Pick what should happen
Choose a recipe below.
- 2
Paste a few lines
A script or an address. The steps say where.
- 3
It runs by itself
We send a message each time. Press Send test to check.
Spreadsheets
Every lead, answer or scan becomes a row.
New leads into Google SheetsGoogle Sheets · 5 minEvery person who leaves their details on a code becomes a new row.
- Open the Google Sheet you want the leads in, then choose Extensions, Apps Script.
- Delete what is there and paste the script below.
- Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add it here as a webhook for New lead, then press Send test. Every new lead now adds a row.
Apps Script
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "lead.captured") return ContentService.createTextOutput("ignored");
var lead = event.data.lead;
SpreadsheetApp.getActiveSheet().appendRow([
new Date(lead.submitted_at), event.data.code.label, lead.name, lead.email, lead.phone
]);
return ContentService.createTextOutput("ok");
}This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
Every form answer into Google SheetsGoogle Sheets · 5 minEach form response becomes a row, with a heading for every question.
- Open an empty Google Sheet, then choose Extensions, Apps Script.
- Paste the script below. It writes the question names as the first row by itself.
- Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add it here as a webhook for Form response, pick the form's folder or leave it for all, then press Send test.
Apps Script
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "form.response") return ContentService.createTextOutput("ignored");
var sheet = SpreadsheetApp.getActiveSheet();
var r = event.data.response;
if (sheet.getLastRow() === 0) sheet.appendRow(["Submitted"].concat(r.columns));
sheet.appendRow([new Date(r.submitted_at)].concat(r.values));
return ContentService.createTextOutput("ok");
}This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
Scans into Google SheetsGoogle Sheets · 5 minTime, code, device, country and where the scan came from, one row per scan, in batches.
- Open an empty Google Sheet, then choose Extensions, Apps Script.
- Paste the script below.
- Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add it here as a webhook for Scan batch. Scans arrive every few minutes in a group, not one at a time.
Apps Script
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "scan.batch") return ContentService.createTextOutput("ignored");
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getLastRow() === 0) sheet.appendRow(["Time", "Code", "Device", "System", "Browser", "Country", "From"]);
event.data.scans.forEach(function (s) {
sheet.appendRow([new Date(s.at), s.code.label, s.device, s.os, s.browser, s.country, s.referrer]);
});
return ContentService.createTextOutput("ok");
}Chat and alerts
Know the moment something happens, in the place you already look.
New leads in SlackSlack · 10 minA message in your team channel the moment someone leaves their details.
- In Slack create an Incoming Webhook for the channel you want and copy its address.
- Open a new Google Apps Script project and paste the script below.
- In Project Settings, Script properties add
SLACK_URLwith the Slack address as its value. - Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add the web app address here as a webhook for New lead and press Send test.
Apps Script
// In the Apps Script editor open Project Settings, add a Script property named SLACK_URL
// and paste your Slack incoming webhook address as its value.
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "lead.captured") return ContentService.createTextOutput("ignored");
var lead = event.data.lead;
var text = "New lead from " + event.data.code.label + ": " + (lead.name || "no name") +
(lead.phone ? ", " + lead.phone : "") + (lead.email ? ", " + lead.email : "");
UrlFetchApp.fetch(PropertiesService.getScriptProperties().getProperty("SLACK_URL"), {
method: "post", contentType: "application/json", payload: JSON.stringify({ text: text })
});
return ContentService.createTextOutput("ok");
}Slack does not read QR Studio's message directly, so a small script in the middle turns it into a sentence.
This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
"Your code passed 1,000 scans" in team chatSlack, Discord or Google Chat · 10 minA celebration, or a nudge, in Slack, Discord or Google Chat.
- Make an incoming webhook in your chat tool for the room you want, and copy its address.
- Open a new Google Apps Script project and paste the script below.
- In Project Settings, Script properties add
CHAT_URL(the address) andCHAT(the wordslack,discordorgoogle). - Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add the web app address here as a webhook for Milestone reached and press Send test.
Apps Script
// Script properties: CHAT_URL = your incoming webhook address, CHAT = slack, discord or google
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "milestone.reached") return ContentService.createTextOutput("ignored");
var p = PropertiesService.getScriptProperties();
var d = event.data;
var text = d.code.label + " passed " + d.milestone + " scans (" + d.total_scans + " so far)";
var body = p.getProperty("CHAT") === "discord" ? { content: text } : { text: text };
UrlFetchApp.fetch(p.getProperty("CHAT_URL"), { method: "post", contentType: "application/json", payload: JSON.stringify(body) });
return ContentService.createTextOutput("ok");
}Alert on your phone when a page stops loadingTelegram · 10 minA Telegram message before your customers notice a broken link.
- In Telegram talk to @BotFather, make a bot, and keep the token it gives you.
- Send your new bot any message, then find your chat number (search for "telegram getUpdates chat id" for the one-minute way).
- Open a new Google Apps Script project and paste the script below.
- In Project Settings, Script properties add
TELEGRAM_TOKENandTELEGRAM_CHAT. - Open the tool, then choose Deploy, New deployment, Web app. Set "Who has access" to Anyone and press Deploy.
- Copy the web app address (it starts with
https://script.google.com/macros/). - Add the web app address here as a webhook for Destination broken and press Send test.
Apps Script
// Script properties: TELEGRAM_TOKEN = the token from BotFather, TELEGRAM_CHAT = your chat number
function doPost(e) {
var event = JSON.parse(e.postData.contents);
if (event.type !== "destination.broken") return ContentService.createTextOutput("ignored");
var p = PropertiesService.getScriptProperties();
var d = event.data;
var text = "Check this QR code: " + d.code.label + ". Its page on " + d.destination_host +
" is not loading" + (d.http_status ? " (error " + d.http_status + ")" : "") + ".";
UrlFetchApp.fetch("https://api.telegram.org/bot" + p.getProperty("TELEGRAM_TOKEN") + "/sendMessage", {
method: "post", contentType: "application/json",
payload: JSON.stringify({ chat_id: p.getProperty("TELEGRAM_CHAT"), text: text })
});
return ContentService.createTextOutput("ok");
}Workflows
Connect to thousands of apps without writing code.
Start any workflow in Zapier, Make, n8n or PabblyZapier, Make, n8n, Pabbly Connect · 5 minConnect to thousands of apps without writing code.
- Make a new workflow whose first step is a webhook: Webhooks by Zapier, Catch Hook, Make's Custom webhook, n8n's Webhook node, or Pabbly's Webhook trigger.
- Copy the address it gives you and add it here as a webhook. Choose the events you care about.
- Press Send test so the tool sees the shape of the data, then add your next step: Google Sheets, an email, a CRM, a message.
The tools have free and paid plans of their own. QR Studio only sends the message.
This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
Message new leads on WhatsAppZapier, Make or Pabbly with a WhatsApp provider · 20 minSend a thank-you or a coupon to the number a visitor left.
- Start a workflow in Zapier, Make or Pabbly Connect with a webhook as its first step (see the recipe above).
- Add this webhook address here for New lead, then press Send test.
- Add a WhatsApp step from a provider you have an account with (WhatsApp Business through Twilio, Gupshup, Interakt, Wati and others) and use the lead's phone and name from the test message.
- Only message people who ticked the consent box on your code. The message carries
consent: truefor that reason.
WhatsApp charges per message, and a business message needs an approved template. Both are between you and the provider.
This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
Your own software
Receive every event on your server, and check it is really from us.
Receive messages on your own serverYour own server (Node.js shown) · 20 minYour software gets every event and checks it really came from QR Studio.
- Run the script below somewhere with a public https address (for example behind your web server).
- Set the environment variable
QRSTUDIO_SECRETto the signing secret shown once when you make the webhook. - Add your https address here as a webhook and press Send test. Reply with any
2xxstatus within 5 seconds, or the message is tried again.
Node.js
const http = require("node:http");
const crypto = require("node:crypto");
// The signing secret QR Studio showed once when you made the webhook.
const SECRET = process.env.QRSTUDIO_SECRET;
function isFromQrStudio(raw, header) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (!parts.t || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false; // too old
const expected = crypto.createHmac("sha256", SECRET).update(parts.t + "." + raw).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
http.createServer((req, res) => {
const chunks = [];
req.on("data", (c) => chunks.push(c));
req.on("end", () => {
const raw = Buffer.concat(chunks).toString("utf8");
if (!isFromQrStudio(raw, req.headers["x-qrstudio-signature"] || "")) {
res.statusCode = 401;
return res.end("bad signature");
}
const event = JSON.parse(raw);
console.log(event.type, JSON.stringify(event.data));
res.end("ok");
});
}).listen(3000);This message carries a visitor’s name, email or phone. You are responsible for how it is used, and for having their consent.
Questions
- What is a webhook?
- A message QR Studio sends to another app the moment something happens: a visitor leaves their details, someone answers a form, a code passes 1,000 scans, or a code's page stops loading.
- Do I need to write code?
- Not for Zapier, Make, n8n or Pabbly. For Google Sheets, Slack and Telegram you paste a short script we give you, and the steps say exactly where. You only write code if you receive messages on your own server.
- Which plans include it?
- Webhooks are on Pro (3 of them) and Agency (10). The recipes are free to read, so you can see what you would get.
- Are the messages safe?
- Only https addresses are allowed. Each message is signed with a secret that only you have, so your server can check it really came from QR Studio. If your address is down, we try again several times over the next 12 hours.
- Is there an API?
- An API with keys, for making and managing codes from your own software, is planned. Join the waitlist from the top bar to hear when it is ready.