How to Monitor Stimulus with Vigilmon
Stimulus is a modest JavaScript framework that connects HTML to JavaScript controllers without replacing your server-rendered markup. Because Stimulus enhances existing HTML rather than replacing it, the real risk in a Stimulus app isn't the JavaScript — it's the server that renders the HTML in the first place. If your Rails, Django, or Node backend goes down, Stimulus has nothing to enhance.
This tutorial covers:
- A
/healthendpoint on your backend - An HTTP uptime monitor in Vigilmon
- A keyword monitor that confirms
data-controllerattributes are present in your rendered HTML - Alerts when the backend or Stimulus markup breaks
Setup takes about 15 minutes.
Step 1: Add a health endpoint to your backend
Stimulus runs on top of a server-rendered backend. Add a /health route there:
Rails:
# config/routes.rb
get '/health', to: 'health#show'
# app/controllers/health_controller.rb
class HealthController < ApplicationController
skip_before_action :authenticate_user!, if: :health_check?
def show
checks = {}
healthy = true
begin
ActiveRecord::Base.connection.execute('SELECT 1')
checks[:database] = 'ok'
rescue => e
checks[:database] = 'error'
healthy = false
end
status = healthy ? :ok : :service_unavailable
render json: {
status: healthy ? 'ok' : 'degraded',
checks: checks,
timestamp: Time.current.iso8601
}, status: status
end
private
def health_check?
action_name == 'show'
end
end
Django:
# health/views.py
from django.http import JsonResponse
from django.db import connection
from django.utils import timezone
def health(request):
checks = {}
healthy = True
try:
with connection.cursor() as cursor:
cursor.execute('SELECT 1')
checks['database'] = 'ok'
except Exception:
checks['database'] = 'error'
healthy = False
status = 200 if healthy else 503
return JsonResponse({
'status': 'ok' if healthy else 'degraded',
'checks': checks,
'timestamp': timezone.now().isoformat(),
}, status=status)
# urls.py
from django.urls import path
from health.views import health
urlpatterns = [path('health/', health)]
Test it:
curl http://localhost:3000/health
# {"status":"ok","checks":{"database":"ok"},"timestamp":"..."}
Step 2: Set up an HTTP monitor in Vigilmon
Deploy your app, then connect it to Vigilmon:
- Sign up at vigilmon.online — free, no card required
- Click New Monitor → HTTP
- URL:
https://yourapp.example.com/health - Check interval: 1 minute (paid) or 5 minutes (free)
- Expected status:
200 - Save
Step 3: Add a keyword monitor for Stimulus markup
The HTTP monitor tells you the server is up. A keyword monitor tells you the server is rendering the right HTML — including the data-controller attributes that Stimulus needs to wire up your JS.
In Vigilmon:
- Click New Monitor → Keyword
- URL:
https://yourapp.example.com/ - Keyword:
data-controller(or a more specific value likedata-controller="dropdown") - Match type: Contains
- Expected status:
200 - Save
If your template engine fails or a layout breaks, the data-controller attributes disappear and your Stimulus controllers silently stop working. The keyword monitor catches this before users report it.
You can also add a keyword monitor for your Stimulus JS bundle:
- Click New Monitor → Keyword
- URL:
https://yourapp.example.com/ - Keyword: the script tag or bundle path, e.g.
stimulusorcontrollers/index - Match type: Contains
- Save
Step 4: Configure alerts
Go to Notifications → New Channel in Vigilmon:
Slack:
- Create an incoming webhook at api.slack.com/apps
- Paste the URL into Vigilmon's Slack channel config
- Enable it on all your monitors
Email:
- Add your email under Notifications
- Enable for the monitors you care about
Sample alert:
🔴 DOWN: yourapp.example.com/health
Status: 503
Region: EU-West
1 minute ago
Recovery:
✅ RECOVERED: yourapp.example.com/health
Downtime: 3 minutes
Step 5: Heartbeat monitoring for background jobs
Many Stimulus apps rely on backend jobs for things like sending emails, processing uploads, or syncing data. Add a heartbeat for each critical job.
Rails (with Sidekiq):
# app/jobs/daily_sync_job.rb
class DailySyncJob < ApplicationJob
queue_as :default
def perform
# ... your sync logic
heartbeat_url = ENV['VIGILMON_SYNC_HEARTBEAT']
Net::HTTP.get(URI(heartbeat_url)) if heartbeat_url
end
end
Django (with Celery):
# tasks.py
import os, requests
from celery import shared_task
@shared_task
def daily_sync():
# ... your sync logic
url = os.environ.get('VIGILMON_SYNC_HEARTBEAT')
if url:
requests.get(url, timeout=5)
In Vigilmon:
- Click New Monitor → Heartbeat
- Set the interval to match your job schedule
- Copy the ping URL into your environment config
Step 6: Public status page
Go to Status Pages → New Status Page, add your monitors, and publish. Share the link with users so they can self-check during incidents:
Something broken? Check our status page: https://status.yourapp.example.com
Embed a badge in your README:

What you've built
| What | How |
|------|-----|
| Health endpoint | Rails/Django route at /health |
| HTTP uptime check | Vigilmon HTTP monitor |
| Stimulus markup check | Vigilmon keyword monitor for data-controller |
| Slack/email alerts | Vigilmon notification channels |
| Background job monitoring | Heartbeat ping in Sidekiq/Celery job |
| Status page | Vigilmon public status page |
Stimulus keeps your frontend simple. Vigilmon keeps your backend visible when things break.
Next steps
- Add keyword monitors for other critical
data-controllerattributes on key pages (e.g. checkout, search) - Watch response time trends — slow server renders hurt Stimulus page interactions before causing outages
- Add a heartbeat for every background job in your stack
Get started free at vigilmon.online.