Send Slack Alerts from your App using Slack Webhook URLs
Sending alerts from your production services to your Slack workspace can speed up your team's responses to incidents and sales opportunities. This article will walk you through integrating with the Slack API from a Remix application.
Sam Magura
Slack is one of the leading platforms for real-time communication. But the platform is useful for more than just messaging your coworkers — Slack is also a convenient place to aggregate and monitor alerts from across your business. For example, your development team may want to receive an alert when a production server's CPU usage exceeds a certain threshold, and your sales team may want to receive an alert when a new lead is acquired.
Having these alerts in Slack allows your teams to react more quickly than if the alert was sent as an email. Decreasing the time between an alert being generated and a team member taking action can have a huge impact, for example if the alert indicates that a production system is about to go down.
The other good thing is that integrating your services with the Slack API is incredibly easy. Simply create a Slack app, and then you can send Slack messages from your code by making HTTP POST calls to the app's webhook URL.
The rest of this article will provide a step-by-step guide to sending Slack messages from your application, with the Slack webhook URL retrieved from Zero at runtime. We'll be using the Remix full stack JavaScript framework, but the steps can easily be adapted to any programming environment that allows you to make HTTP calls.
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
Secure your secrets conveniently
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.
Creating a Slack App
Before we can start sending messages from our code, we need to create a Slack app and connect it to our Slack workspace. You can do this by following these steps:
- Go to https://api.slack.com/apps .
- Click "Create New App".
- Select "From scratch".
- Enter a name for the app and select your workspace.
- Under "Add features and functionality", select "Incoming Webhooks". Turn the toggle to "on".
- Click "Add New Webhook to Workspace".
- Select the the channel you want your app to post to. We'll be using a dedicated #alerts channel.
- Copy the webhook URL, which will look something like
https://hooks.slack.com/services/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
. Your URL is a secret and should not be shared publicly or committed to your git repository.
If you want, you can copy the sample Curl request and run it in a terminal to verify that the app is working.
Adding the Webhook URL as a Secret in Zero
We can simplify our application's configuration by storing the webhook URL in Zero with the rest of our API keys. To do so, log in to Zero and create a new project. Then click the "Add secret" button and fill out the form as shown here:
Creating the Remix Application
Remix is a relatively new full stack JavaScript application framework that is based on React. Overall, Remix is fairly similar to Next.js , but is faster and offers a unified model for data fetching. Though, the Next.js team seems likely to catch up to Remix with the new app
directory that was launched with Next.js 13 as a beta feature. While we'll be using Remix in this guide, you can follow roughly the same steps if working with Next.js or any other web application framework.
To create a new Remix application, run npx create-remix@latest slack-alerts
and answer the questions when prompted:
npx create-remix@latest slack-alerts
? What type of app do you want to create? Just the basics
? Where do you want to deploy? Choose Remix App Server if you're unsure; it's easy to change deployment targets. Vercel
? TypeScript or JavaScript? TypeScript
? Do you want me to run `npm install`? Yes
Feel free to choose whichever deployment target your prefer — it won't affect the code we write to integrate with Slack.
Our application only needs to contain a single page, so we can put our UI code directly in app/routes/index.tsx
. Let's render a simple form that asks for the user's name and the alert text they would like to send to Slack:
The code for the form will look something like this:
export default function Index() {
const actionData = useActionData<ActionData>()
const errors = actionData?.errors
return (
<div>
<h1>Create an Alert in Slack</h1>
<Form method="post">
<div className="form-group">
<label htmlFor="nameInput">Your name</label>
<input id="nameInput" name="name" />
{errors?.name && <p className="validation-error">{errors.name}</p>}
</div>
<div className="form-group">
<label htmlFor="textInput">Alert text</label>
<textarea id="textInput" name="text" rows={6} />
{errors?.text && <p className="validation-error">{errors.text}</p>}
</div>
<button type="submit">Create alert</button>
</Form>
{actionData?.success && <p className="success">Created alert!</p>}
</div>
)
}
When the form is submitted, it will execute the action
function which is defined in the same file. Our action will validate the form data and then call createAlert()
if everything looks good.
type ActionData =
| {
success: boolean
errors?: {
name: null | string
text: null | string
}
}
| undefined
export const action: ActionFunction = async ({request}) => {
const formData = await request.formData()
const name = formData.get('name') as string | null
const text = formData.get('text') as string | null
const errors = {
name: name ? null : 'Name is required.',
text: text ? null : 'Alert text is required.',
}
const hasErrors = Object.values(errors).some((errorMessage) => errorMessage)
if (hasErrors) {
return json<ActionData>({success: false, errors})
}
await createAlert({name: name!, text: text!})
return json<ActionData>({success: true})
}
Sending the Alert
The next step is to implement createAlert
. This function will run server side and send an HTTP POST to the Slack webhook URL, using the data that was submitted through the form. The createAlert
function should be placed in app/models/alert.server.ts
:
interface CreateAlertOptions {
name: string
text: string
}
export async function createAlert({name, text}: CreateAlertOptions): Promise<void> {
const slackWebhookUrl = await getSlackWebhookUrl()
const body = JSON.stringify({text: `${name} created a new alert: ${text}`})
// Node 18+ is required to use the built-in `fetch` function
const response = await fetch(slackWebhookUrl, {
method: 'POST',
body,
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
let responseText = ''
try {
responseText = await response.text()
} catch {}
throw new Error(
`Posting to Slack returned a ${response.status} status code. ` + `The response was:\n\n${responseText}`,
)
}
}
Here, getSlackWebhookUrl
is a function that will retrieve the secret webhook URL from Zero using the Zero TypeScript SDK. You can install the SDK with
npm install @zerosecrets/zero
and use it like so:
import {zero} from '@zerosecrets/zero'
let slackWebhookUrl: string | undefined
export async function getSlackWebhookUrl(): Promise<string> {
// Don't call Zero on every request
if (slackWebhookUrl) {
return slackWebhookUrl
}
if (!process.env.ZERO_TOKEN) {
throw new Error('Did you forget to set the ZERO_TOKEN environment variable?')
}
const secrets = await zero({
token: process.env.ZERO_TOKEN,
pick: ['slack'],
}).fetch()
slackWebhookUrl = secrets.slack?.['ALERTS_WEBHOOK_URL']
if (!slackWebhookUrl) {
throw new Error('Did not receive the Slack webhook URL.')
}
return slackWebhookUrl
}
Now when you run your app, you'll need to provide the Zero token as an environment variable:
ZERO_TOKEN='YOUR-ZERO-TOKEN' npm run dev
If you were deploying this to a platform like Vercel, the Zero token should also be added as an environment variable through the Vercel UI.
Finally try running the app and entering a name and the content of your alert. If it works, you'll see the alert in your Slack workspace!
Conclusion
This article showed how to send a message to a Slack channel from your code using the Slack API. We used Remix for our demonstration app, but you can integrate with Slack just as easily from any other web framework.
While our simple app had the user manually creating an alert, similar to PagerDuty, it is even more powerful to automatically create alerts when certain events occur (like when the load on your database exceeds some threshold). In these scenarios, you can use the exact same code that was shown in this article to create the alert. The more involved part is figuring out how to integrate with the monitoring system you use to determine when an alert should be sent.
Other articles
Build an Email Summary Bot using Claude AI, Gmail, and Slack (Part 2)
Use the Claude AI assistant to summarize emails in just a few lines of code.
Build an Email Summary Bot using Claude AI, Gmail, and Slack (Part 1)
Integrate with the Gmail Push Notifications API to enable your app to intelligently respond to new emails.
Secure your secrets
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.