Skip to main content
Version: v2

Notifications

Vortex announces each deployment on the channels you turn on, so your team hears about a new environment, and gets a link to log in to it, without watching CI.

This page is for the lead or DevOps engineer who sets up deployment notifications. It explains when notifications go out, how to pick the channels, and the settings that every channel shares. Each channel's own page covers its setup and its variables.

The vendor/bin/vortex-notify router script dispatches the notifications. It checks the shared variables, collects the deployment logs, and then runs the script of each channel you turn on. The hosting platform runs the router around a deployment, from the Lagoon post-rollout tasks or the Acquia Cloud Hooks, and the CI deploy job never does. The hosting side is where the environment's URL is known: the Lagoon tasks read it from LAGOON_ROUTE, and the Acquia hook builds it from the site name.

On Lagoon, the router runs twice per deployment: with the pre_deployment event before provisioning, and with post_deployment after it. The Acquia hook runs it once, after the deployment, with the default post_deployment event.

Channels​

Configure notification channels in your .env file:

.env
# Enable notification channels (comma-separated list)
VORTEX_NOTIFY_CHANNELS=email,slack,github

The router supports 7 channels and runs them in the order you list them:

  • email - sends an email to a list of recipients.
  • slack - posts a message to a Slack channel.
  • newrelic - records a deployment marker in New Relic APM.
  • github - reports the deployment through the GitHub Deployments API.
  • jira - comments on the Jira issue named in the branch.
  • webhook - sends a JSON payload to a URL you choose.
  • diffy - starts a Diffy visual regression run through GitHub Actions.

The default is email, and an empty value falls back to it, so to turn notifications off, set VORTEX_NOTIFY_SKIP instead. The Vortex CLI offers every channel except diffy, which you add by hand. A name that matches no channel stops the router with Notification script for channel and the misspelled name.

When a channel fails, the router stops with an error, and the channels after it don't run. On Lagoon, the failed notification task stops the post-rollout tasks after it, and Lagoon notifies you about the failure. So a failure at pre_deployment skips provisioning too. On Acquia, the notification hook runs last: Acquia marks the deployment task as failed, and the hook's output appears in the task log.

Global environment variables​

These variables apply to every channel unless a channel-specific variable overrides them. The Variables reference lists the project-level variables that .env sets.

The Location column in this section and on the channel pages says where a value usually lives. .env holds project-wide settings that you commit. Hosting means secrets and per-deployment values: you set them in the hosting platform's environment variables, or the hosting hook and the router set them at run time.

The following table lists the global variables:

VariableRequiredDefaultLocationDescription
VORTEX_NOTIFY_CHANNELSNoemail.envNotification channels (comma-separated)
VORTEX_NOTIFY_PROJECTNoVORTEX_PROJECTHostingNotification project name; the Lagoon tasks set it to LAGOON_PROJECT and the Acquia hook to the site name
VORTEX_NOTIFY_SKIPNoNoneHostingSet to 1 to skip notifications; any value other than empty or 0 skips them

Deployment context variables​

These variables hold the deployment details that the channels read. The hosting platform has to set them before it calls the router, and the shipped Lagoon post-rollout tasks and Acquia hook already do. The router stops with Missing required value for and the variable name when a required one is empty.

The following table lists the deployment context variables and what the Lagoon tasks and the Acquia hook put in them:

VariableRequiredDescription
VORTEX_NOTIFY_BRANCHYesGit branch name. Lagoon: the pull request's head branch, or LAGOON_GIT_BRANCH. Acquia: the source branch argument that Acquia passes to the hook
VORTEX_NOTIFY_SHAYesDeployed reference. Lagoon: the commit SHA in LAGOON_GIT_SHA. Acquia: the deployed tag argument that Acquia passes to the hook, a name rather than a commit SHA
VORTEX_NOTIFY_PR_NUMBERNoPull request number. Lagoon: LAGOON_PR_NUMBER. Empty on Acquia and for branch deployments
VORTEX_NOTIFY_LABELYesHuman-readable deployment label. Lagoon: PR-<number> for pull requests, the branch name otherwise. Acquia: the same value as VORTEX_NOTIFY_BRANCH
VORTEX_NOTIFY_ENVIRONMENT_URLYesURL of the deployed environment, used by the %environment_url% token. Lagoon: LAGOON_ROUTE. Acquia: built from AH_SITE_NAME and AH_REALM, or from VORTEX_NOTIFY_ENVIRONMENT_DOMAIN
VORTEX_NOTIFY_LOGIN_URLNoLogin URL for the %login_url% token; defaults to <environment_url>/user/login
VORTEX_NOTIFY_EVENTNoDeployment event: post_deployment (default) or pre_deployment; any other value fails the run with Unsupported event. Lagoon: pre_deployment, then post_deployment. Acquia: not set, so post_deployment

Only Slack and GitHub act on pre_deployment; the other 5 channels skip it.

Branch filtering​

You can limit each channel to specific branches with its VORTEX_NOTIFY_<CHANNEL>_BRANCHES variable. When it's set, the channel sends notifications only for deployments on the listed branches. The list is comma-separated, and each entry is an exact branch name, not a pattern. When the variable is empty or unset, the channel runs on all branches.

Email, Slack, New Relic, and webhook compare the list with VORTEX_NOTIFY_BRANCH. GitHub, Jira, and Diffy compare it with their own branch variable, such as VORTEX_NOTIFY_JIRA_BRANCH, which defaults to VORTEX_NOTIFY_BRANCH.

For example, to restrict New Relic notifications to only main and staging:

VORTEX_NOTIFY_NEWRELIC_BRANCHES=main,staging

New Relic defaults to main,master,develop. All other channels default to no filter. An empty New Relic value falls back to that default, so to let New Relic run on other branches, list every branch you want.

Message templates and tokens​

The following channels take custom templates:

  • Email: VORTEX_NOTIFY_EMAIL_SUBJECT and VORTEX_NOTIFY_EMAIL_MESSAGE
  • Slack: VORTEX_NOTIFY_SLACK_MESSAGE
  • New Relic: VORTEX_NOTIFY_NEWRELIC_DESCRIPTION
  • Webhook: VORTEX_NOTIFY_WEBHOOK_MESSAGE and VORTEX_NOTIFY_WEBHOOK_PAYLOAD

GitHub, Jira, and Diffy send fixed payloads. The templates use the replacement tokens in the following table:

TokenDescriptionExample
%project%Project nameMy Project
%label%Deployment labelmain or PR-123
%timestamp%Current timestamp15/11/2025 14:30:45 UTC
%environment_url%Environment URLhttps://example.com
%login_url%Login URLhttps://example.com/user/login
%deployment_log%Collected deployment logs, when enabled (email message and webhook only)A ## provision.log ## heading, then the log text
%message%The webhook message with the other tokens replaced (webhook payload only)The default message, filled in

The default message template is:

## This is an automated message ##
Site %project% %label% has been deployed at %timestamp% and is available at %environment_url%.
Login at: %login_url%

Slack uses it as the message's fallback text. The email and webhook defaults add a blank line and %deployment_log% at the end. Jira posts the same text as a formatted comment, and New Relic's default description is its middle line, without the final period.

Deployment log​

Notifications can include the logs that deployment scripts write. Each producing script writes its own <name>.log into VORTEX_NOTIFY_LOG_DIR; vortex-provision writes provision.log there when VORTEX_PROVISION_LOG=1, truncating it at the start of each run. When VORTEX_NOTIFY_LOG=1, the router collects every non-empty log in that directory, each as its own titled section. It passes the path of the collected file to the channels as VORTEX_NOTIFY_LOG_FILE, which stays empty when it collected nothing.

The email, Slack, Jira, and webhook channels add the collected logs to their message, each in its own way:

  • Email and webhook templates insert them at the %deployment_log% token. The default email message ends with that token, and the default webhook payload carries it at the end of message. A custom template without the token leaves the logs out.
  • Slack adds them to the message attachment.
  • Jira posts them as a code block after the comment text.

GitHub, New Relic, and Diffy never include logs.

To include the provision log in notifications, set both VORTEX_PROVISION_LOG=1 and VORTEX_NOTIFY_LOG=1 (in .env or per environment).

Each of those 4 channels also reads a flag of its own:

  • VORTEX_NOTIFY_EMAIL_LOG
  • VORTEX_NOTIFY_SLACK_LOG
  • VORTEX_NOTIFY_JIRA_LOG
  • VORTEX_NOTIFY_WEBHOOK_LOG

A flag set to 1 includes the collected logs in that channel, and 0 leaves them out. Each flag defaults to the value of VORTEX_NOTIFY_LOG, so with VORTEX_NOTIFY_LOG=1, all 4 channels include the logs. To leave the logs out of a single channel, set its flag to 0 (for example VORTEX_NOTIFY_SLACK_LOG=0). A channel flag can't add logs on its own: the router collects logs only when VORTEX_NOTIFY_LOG=1.

warning

Deployment logs go out verbatim. Make sure producing scripts don't print secrets, and turn the feature on only for the channels and environments where showing the full logs is acceptable.

Producing scripts write their logs to VORTEX_NOTIFY_LOG_DIR (default ./.logs, relative to the directory the scripts run from). vortex-provision creates its log directory and provision.log owner-only (700/600) on a best-effort basis, and the router's combined file (combined) is owner-only too. Any other producing script controls the permissions of its own log file. If you point VORTEX_NOTIFY_LOG_DIR at a custom directory, make sure that location isn't readable by other users.

The following table lists the deployment log variables:

VariableRequiredDefaultLocationDescription
VORTEX_PROVISION_LOGNo0.env or HostingSet to 1 to write the provision log for collection
VORTEX_NOTIFY_LOGNo0.env or HostingSet to 1 to collect and include deployment logs
VORTEX_NOTIFY_LOG_DIRNo./.logs.envDirectory the logs are collected from