Get Slack Alerts When Attendees Checks In to an Event
To track if your VIPs have arrived at the event, you can set up slack alerts as soon as they check in, this way you can greet them at the check in counter. In this article you'll learn how to set up these alerts by using the webhook feature.
How Does it Work?
You will need to create an app in slack that will send the notifications, then add the list of attendees to a Google Sheet with all pertinent information. Next, you will add a code to your Google Sheet's App's Script feature, then add a webhook URL to your Accelevents settings.
If everything is done correctly, the slack user will be tagged in a slack alert in a particular slack channel when their VIP attendee checks in to any of the events under your organizer.
You will need the following:
The list of attendees in a Google Sheets
Access to create an app in your Slack workspace
Access to use App Scripts in Google Sheets
Access to use Webhooks in Accelevents
Create an App in Slack
Go to Slack and click Tools & Settings from your workspace settings, then select Manage Apps.
Click Build, select Create an App, then choose From Scratch.
Add the App Name, select the workspace, and click Create App.
Go to OAuth & Permissions.
Click Add an OAuth Scope and add channels:join, chat:write, im:write, and users:read.
Install the app to your workspace. Click Allow.
Copy the Bot User OAuth Token.
Go back to Slack. You'll see that the app is added.
Invite the app to the Slack channel where the notification alert will be sent to. Mention the app in the channel then click Add Them.
Create the List of Attendees in a Google Sheet
All headers must be present in the sheet and should exactly be the same as below.
Headers | Value |
Check-in Status | This should be left blank, this will automatically be updated when the attendee checks in |
Name | This is the complete name of the attendee |
Email Address | This is the email address of the attendee |
User Slack ID | This is the slack user who will be tagged in the notification. This should be their full name (slack profile name), not their @ handle.
(e.g. Slack profile name: Ariane Ramirez, slack handle @ariane) |
Slack Channel | This is the channel where the notification will be posted. Include the # and - in the channel name
(e.g. #cx-shift-status) |
Notes | This is additional information you want to include in the notification, such as their job title and company. |
Notes:
The sheet with the attendees should be named Sheet1 for it to work.
You can create a blank second sheet named Sheet2 where automatic logs will appear every time a new notification is sent.
You can change the headers, but you must also tweak the script in the next step to match the header names.
Add the AppScript in Google Sheets
In your Google Sheet, click Extensions > App Script. This will open a new tab to add the script.
Paste this script:
// Configuration variables: Change them to suit your spreadsheet. Check your spelling!
var SHEET_NAME = "Sheet1"; // Name of the main sheet containing user data
var EMAIL_COLUMN = "Email Address"; // Column header for email addresses
var SLACK_COLUMN = "User Slack ID"; // Column header for Slack IDs
var SLACK_CHANNEL_COLUMN = "Slack Channel"; // Column header for Slack channels
var NAME_COLUMN = "Name"; // Column header for names
var NOTES_COLUMN = "Notes"; // Column header for additional notes
var CHECKIN_STATUS_COLUMN = "Check-in Status"; // Column header for check-in status
var SLACK_BOT_TOKEN = 'xoxb-7528513823670-7537157910162-mpoqNBbCkHTVBGHOUuw1Cm7i'; // <<<<<<----- Replace with the Bot User OAuth Token from the "Oauth & Permissions" area of your Slack App's settings
/**
* Handles POST requests to the web app.
* This is the entry point for the webhook from Accelevents.
* @param {Object} e - The event object from the POST request
* @return {TextOutput} A response indicating success or failure
*/
function doPost(e) {
// var logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var timestamp = new Date();
// logSheet.appendRow(["Webhook received", timestamp, JSON.stringify(e)]);
try {
var params = JSON.parse(e.postData.contents);
// logSheet.appendRow(["Parsed params", timestamp, JSON.stringify(params)]);
var result = processWebhook(params);
// logSheet.appendRow(["Webhook processing completed", new Date(), JSON.stringify(result)]);
return result;
} catch (error) {
// logSheet.appendRow(["Error in doPost", timestamp, error.toString()]);
return ContentService.createTextOutput("Error: " + error.toString()).setMimeType(ContentService.MimeType.TEXT);
}
}
/**
* Processes the webhook data, updates the spreadsheet, and sends Slack messages.
* @param {Object} params - The parsed webhook payload
* @return {TextOutput} A response indicating success or failure
*/
function processWebhook(params) {
if (!params || !params.data || !params.data.holderEmail) {
Logger.log("Error: Invalid webhook payload. Missing holderEmail.");
return ContentService.createTextOutput("Error: Invalid webhook payload").setMimeType(ContentService.MimeType.TEXT);
}
var emailToSearch = params.data.holderEmail.trim().toLowerCase();
var eventId = params.eventId;
try {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = spreadsheet.getSheetByName(SHEET_NAME);
var logSheet = spreadsheet.getSheetByName("Sheet2");
if (!mainSheet || !logSheet) {
throw new Error("Required sheets not found");
}
logSheet.appendRow([new Date(), JSON.stringify(params)]);
var dataRange = mainSheet.getDataRange();
var data = dataRange.getValues();
var headers = data[0];
var emailColIndex = headers.indexOf(EMAIL_COLUMN);
var slackColIndex = headers.indexOf(SLACK_COLUMN);
var slackChannelColIndex = headers.indexOf(SLACK_CHANNEL_COLUMN);
var nameColIndex = headers.indexOf(NAME_COLUMN);
var notesColIndex = headers.indexOf(NOTES_COLUMN);
var checkinStatusColIndex = headers.indexOf(CHECKIN_STATUS_COLUMN);
if (emailColIndex === -1 || slackColIndex === -1 || slackChannelColIndex === -1 || nameColIndex === -1 || notesColIndex === -1 || checkinStatusColIndex === -1) {
throw new Error("Specified columns not found in the sheet");
}
var slackId = '';
var slackChannel = '';
var name = '';
var notes = '';
var rowFound = false;
for (var i = 1; i < data.length; i++) {
if (data[i][emailColIndex].trim().toLowerCase() === emailToSearch) {
slackId = data[i][slackColIndex];
slackChannel = data[i][slackChannelColIndex];
name = data[i][nameColIndex];
notes = data[i][notesColIndex];
mainSheet.getRange(i + 1, checkinStatusColIndex + 1).setValue("Checked In");
rowFound = true;
Logger.log("Matching row found at index: " + i);
break;
}
}
if (!rowFound) {
Logger.log("No matching row found for email: " + emailToSearch);
}
if (slackId !== '' || slackChannel !== '') {
sendSlackMessage(slackId, slackChannel, emailToSearch, name, eventId, notes);
} else {
Logger.log("No Slack ID or channel provided. Skipping Slack notification.");
}
return ContentService.createTextOutput(JSON.stringify({ 'result': 'success', 'email': emailToSearch, 'rowFound': rowFound })).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
Logger.log("Error in processWebhook: " + error.toString());
return ContentService.createTextOutput("Error: " + error.toString()).setMimeType(ContentService.MimeType.TEXT);
}
}
/**
* Sends Slack messages to both a user (DM) and a channel if specified.
* @param {string} slackId - The Slack ID or username of the recipient
* @param {string} slackChannel - The Slack channel to send the message to (optional)
* @param {string} email - The email of the person who checked in
* @param {string} name - The name of the person who checked in
* @param {string} eventId - The ID of the event
* @param {string} notes - Additional notes about the check-in
*/
function sendSlackMessage(slackId, slackChannel, email, name, eventId, notes) {
var basemessage = email + " (" + name + ") just checked in to event " + eventId + ". " + notes;
var userId = null;
// Find Slack user ID
if (slackId) {
var dmUser = slackId.startsWith('@') ? slackId.substring(1) : slackId; // Remove @ if present
Logger.log("Attempting to find Slack user ID for: " + dmUser);
userId = findSlackUserId(dmUser);
if (!userId) {
Logger.log("Error: Could not find Slack user ID for " + dmUser);
}
}
// Send DM
if (userId) {
var dmPayload = {
"channel": userId,
"text": basemessage
};
sendSlackApiMessage(dmPayload, "DM to " + dmUser);
} else {
Logger.log("No valid Slack user ID found for DM");
}
// Send Channel message
if (slackChannel && slackChannel.startsWith('#')) {
var channelMessage = userId ? "<@" + userId + "> -- " + basemessage : basemessage;
var channelPayload = {
"channel": slackChannel,
"text": channelMessage
};
sendSlackApiMessage(channelPayload, "Channel message to " + slackChannel);
} else {
Logger.log("No valid Slack channel provided for channel message");
}
}
/**
* Sends a message to Slack using the Slack API.
* @param {Object} payload - The payload to send to Slack
* @param {string} logPrefix - A prefix for log messages related to this API call
*/
function sendSlackApiMessage(payload, logPrefix) {
Logger.log(logPrefix + ": Attempting to send message");
var options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify(payload),
"headers": {
"Authorization": "Bearer " + SLACK_BOT_TOKEN
}
};
try {
var response = UrlFetchApp.fetch("https://slack.com/api/chat.postMessage", options);
var responseData = JSON.parse(response.getContentText());
if (responseData.ok) {
Logger.log(logPrefix + ": Message sent successfully");
} else {
Logger.log(logPrefix + ": Error sending message: " + responseData.error);
Logger.log("Full response: " + JSON.stringify(responseData));
}
} catch (error) {
Logger.log(logPrefix + ": Error sending message: " + error.toString());
}
}
/**
* Finds a Slack user's ID based on their username, real name, or ID.
* This function is case-insensitive.
* @param {string} userIdentifier - The username, real name, or ID to search for
* @return {string|null} The user's Slack ID if found, null otherwise
*/
function findSlackUserId(userIdentifier) {
// Check if userIdentifier is undefined, null, or an empty string
if (!userIdentifier) {
Logger.log("Error: Invalid user identifier provided");
return null;
}
var options = {
"method": "get",
"headers": {
"Authorization": "Bearer " + SLACK_BOT_TOKEN
}
};
try {
var response = UrlFetchApp.fetch("https://slack.com/api/users.list", options);
var responseData = JSON.parse(response.getContentText());
if (responseData.ok) {
var lowerUserIdentifier = userIdentifier.toLowerCase();
for (var i = 0; i < responseData.members.length; i++) {
var member = responseData.members[i];
if (member.name && member.name.toLowerCase() === lowerUserIdentifier ||
member.real_name && member.real_name.toLowerCase() === lowerUserIdentifier ||
member.id && member.id.toLowerCase() === lowerUserIdentifier) {
Logger.log("Slack user found: " + member.real_name + " (ID: " + member.id + ")");
return member.id;
}
}
Logger.log("No Slack user found for identifier: " + userIdentifier);
} else {
Logger.log("Error fetching Slack users: " + responseData.error);
if (responseData.error === "not_authed" || responseData.error === "invalid_auth" || responseData.error === "token_expired") {
Logger.log("This appears to be an authentication error. Please check your Slack Bot Token and ensure it has the 'users:read' scope.");
}
}
} catch (error) {
Logger.log("Error fetching Slack users: " + error.toString());
Logger.log("Please ensure your Slack Bot Token is correct and has the 'users:read' scope.");
}
return null;
}
/**
* Creates test data for webhook testing.
* @return {Object} A test webhook payload
*/
function testWebhook() {
var testData = {
"topic": "user_check_in",
"eventId": 106460,
"data": {
"ticketId": 3003840,
"checkInDate": "2024-07-25T18:49:28Z",
"holderEmail": "test@test.com",
"holderFirstName": "Test",
"holderLastName": "User",
"holderCountryCode": "US",
"holderCellNumber": 0,
"checkInType": "IN_PERSON"
}
};
return processWebhook(testData);
}
/**
* Runs a test of the webhook processing and logs the results.
* This function can be manually triggered to test the script.
*/
function runTestWebhook() {
Logger.log("Running test webhook");
var result = testWebhook();
Logger.log("Test result: " + JSON.stringify(result));
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = spreadsheet.getSheetByName("Sheet2");
if (logSheet) {
var logData = logSheet.getDataRange().getValues();
Logger.log("Log sheet contents:");
for (var i = 0, t = logData.length; i < t; i++) {
Logger.log(logData[i]);
}
} else {
Logger.log("Log sheet (Sheet2) not found");
}
}
Replace the existing
SLACK_BOT_TOKEN
in the script with your Bot User OAuth Token that you copied when you were setting up your app in slack. Click Save. Select Deploy and click New Deployment.Click the gear icon and select Web app.
Add a description, choose to execute as yourself, select anyone has access, then click Save.
Click Allow.
Copy the Web app URL
Add the Webhook to Organizer Portal
Go to Integrations > Webhooks In your Organizer Portal or White Label / Enterprise Dashboard
Paste the Web app url to the Your request endpoint URL field
Click Save
Select "User check in" from Webhook Topics
Test if it Works
Check in one of the attendees in the list. You should receive a notification in the slack channel. Sheet 1's Check-in Status column should update and Sheet 2 will also have a log of the notifications sent.