Need a QR‑Based Event Check‑In & Gift Distribution Solution
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Friday
Hi,
Has anyone built something like this before if yes how? here is the requirement: an event check‑in and gift distribution solution using QR codes for quick, formless check‑in and a staff‑controlled desk process for issuing gifts. The solution must automatically record attendance, enforce a strict one‑gift‑per‑user rule, prevent duplicates, and provide real‑time visibility via a live dashboard. What is the best solution for this kind of request?
Regards,
CarolMa
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Friday
Yes, this has been built on ServiceNow before — it's a pattern that combines a few platform capabilities: custom tables, Service Portal (or Now Mobile), QR code scanning, Business Rules for enforcement, and PA/Dashboards for real-time visibility. Here's the full breakdown.
1. Data Model (Custom Scoped App)
You need three core tables:
x_app_event — The Event master record (name, date, venue, max_gifts, status).
x_app_invitee — One record per invited person per event. Key fields: event (reference), user (reference to sys_user), qr_token (unique string/GUID), checked_in (true/false), checkin_time (glide_date_time), gift_issued (true/false), gift_issued_time, gift_issued_by (reference to sys_user).
x_app_checkin_log — Optional audit trail for every scan attempt (success, duplicate, invalid token, etc.).
The qr_token field is the linchpin — it's a GUID generated on invite creation (via Business Rule) and encoded into the QR code.
2. QR Code Generation
When invitees are loaded (via import set, list edit, or a registration portal), a Before Insert Business Rule on x_app_invitee generates the token:
(function executeRule(current, previous) {
current.qr_token = gs.generateGUID();
})(current, previous);
The QR code itself encodes a URL like:
https://<instance>.service-now.com/checkin?token=<qr_token>
To generate the QR image for printing/emailing, you have a few options:
- Use a UI Page or Scripted REST endpoint that renders the QR using a library like
qrcode.json the client side - Use a third-party API via REST Integration Hub to generate QR PNGs (if network egress is allowed)
- Use a Service Portal widget with a client-side JS QR library (most common and simplest)
3. Check-In Flow (Formless, Staff-Scanned)
Build a Service Portal page (/checkin) with a single widget:
How it works:
- Staff opens the page on a tablet/phone at the check-in desk
- The page activates the device camera using a JS library like
html5-qrcodeorjsQR - On scan, the QR URL's
tokenparameter is extracted - The widget's Server Script looks up the invitee and processes check-in:
// Server Script (SP Widget)
if (input && input.token) {
var gr = new GlideRecord('x_app_invitee');
gr.addQuery('qr_token', input.token);
gr.addQuery('event.status', 'active');
gr.query();
if (!gr.next()) {
data.status = 'error';
data.message = 'Invalid or unrecognized QR code.';
} else if (gr.checked_in == true) {
data.status = 'duplicate';
data.message = gr.user.getDisplayValue() + ' is already checked in.';
data.checkin_time = gr.getValue('checkin_time');
} else {
gr.checked_in = true;
gr.checkin_time = new GlideDateTime();
gr.update();
data.status = 'success';
data.message = 'Welcome, ' + gr.user.getDisplayValue() + '!';
}
}
Client Script handles camera, decodes QR, calls server, and shows a big green/red/yellow status banner. The whole interaction takes under 2 seconds — no forms, no typing.
4. Gift Distribution (Staff-Controlled Desk)
A separate Service Portal page (/giftdesk) — this one can use either QR scan again or a manual lookup:
Enforcement logic (Server Script):
if (input && input.token) {
var gr = new GlideRecord('x_app_invitee');
gr.addQuery('qr_token', input.token);
gr.query();
if (!gr.next()) {
data.status = 'error';
data.message = 'Invalid token.';
} else if (gr.checked_in != true) {
data.status = 'not_checked_in';
data.message = gr.user.getDisplayValue() + ' has NOT checked in yet. Cannot issue gift.';
} else if (gr.gift_issued == true) {
data.status = 'already_issued';
data.message = 'Gift already issued to ' + gr.user.getDisplayValue()
+ ' at ' + gr.getValue('gift_issued_time')
+ ' by ' + gr.gift_issued_by.getDisplayValue();
} else {
gr.gift_issued = true;
gr.gift_issued_time = new GlideDateTime();
gr.gift_issued_by = gs.getUserID();
gr.update();
data.status = 'success';
data.message = 'Gift issued to ' + gr.user.getDisplayValue();
}
}
The one-gift-per-user rule is enforced at three levels:
- Application logic (above) — primary enforcement
- Business Rule on update — secondary guard that prevents
gift_issuedfrom being set to true if it's already true - ACL — only gift desk staff role can modify
gift_issued
5. Duplicate Prevention
Multiple layers:
- Unique index on
qr_tokenin the table definition — prevents duplicate tokens - Unique compound index on
event + user— prevents the same person being invited twice to the same event - Check-in Business Rule —
Before Updaterule that blocks re-check-in ifchecked_inwas already true and someone tries to toggle it - Concurrency — if two staff scan the same QR simultaneously, the Business Rule + GlideRecord
update()behavior handles this (last-write-wins is fine since the first scan already set it to true; the second scan will hit the "already checked in" branch on read)
6. Real-Time Dashboard
Option A — Performance Analytics (preferred for production):
- Create PA indicators: "Total Checked In", "Total Gifts Issued", "Pending Gifts" (checked in but no gift)
- PA Breakdown by time (hourly check-in rate), by department, etc.
- Embed in a Now Experience/Workspace dashboard with auto-refresh
Option B — Service Portal Dashboard Widget (simpler, event-day focused):
- A widget that runs aggregate queries and refreshes every 10–15 seconds:
// Server script
var counts = {};
var ga = new GlideAggregate('x_app_invitee');
ga.addQuery('event', input.event_id);
ga.addAggregate('COUNT');
ga.query();
if (ga.next()) counts.total = parseInt(ga.getAggregate('COUNT'));
ga = new GlideAggregate('x_app_invitee');
ga.addQuery('event', input.event_id);
ga.addQuery('checked_in', true);
ga.addAggregate('COUNT');
ga.query();
if (ga.next()) counts.checked_in = parseInt(ga.getAggregate('COUNT'));
// ... same pattern for gift_issued
data.counts = counts;
Client-side uses $interval (AngularJS) or setInterval to poll every 10 seconds, displaying live tiles with counts and a progress bar.
Option C — AMB (Ambient Messaging Bus) for true real-time:
- Publish events to an AMB channel on each check-in/gift issuance
- Dashboard widget subscribes to the channel and updates instantly without polling
- This is the most responsive option but adds complexity
7. Summary Architecture
[Invitee Import] → generates QR tokens → [Email/Print QR codes]
│
┌─────────────────────────┤
▼ ▼
[Check-In Desk] [Gift Desk]
SP Widget + Camera SP Widget + Camera/Lookup
Scans QR → auto check-in Scans QR → validates check-in
→ enforces 1-gift rule
→ issues gift
│ │
▼ ▼
[x_app_invitee table - single source of truth]
│
▼
[Live Dashboard]
PA / SP Widget / AMB
Key Tips
- Test with concurrent scans — have two people scan the same QR at the same time to verify your duplicate prevention holds.
- Offline consideration — if venue WiFi is unreliable, consider a fallback manual check-in mode that syncs later.
- Print badge on check-in — you can trigger a print action (via browser print API) to print a name badge right after successful check-in.
- Use roles — create
x_app.checkin_staffandx_app.gift_staffroles to control who can do what. - Audit — log every scan attempt (success or failure) to
x_app_checkin_logfor post-event reporting.
This entire solution can be built as a scoped app, is fully contained within ServiceNow, and typically takes 2–3 days to build and test for someone comfortable with Service Portal widgets and custom tables.
