Need a QR‑Based Event Check‑In & Gift Distribution Solution

CarolMa6
Tera Expert

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

1 REPLY 1

Naveen20
ServiceNow Employee

 

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.js on 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:

  1. Staff opens the page on a tablet/phone at the check-in desk
  2. The page activates the device camera using a JS library like html5-qrcode or jsQR
  3. On scan, the QR URL's token parameter is extracted
  4. 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_issued from 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_token in 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 RuleBefore Update rule that blocks re-check-in if checked_in was 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_staff and x_app.gift_staff roles to control who can do what.
  • Audit — log every scan attempt (success or failure) to x_app_checkin_log for 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.