Home/Guides/Send a push notification from Ruby
Guide · Ruby

How to send a push notification from Ruby

A rake task finishes, an import wraps up, a Sidekiq job hits a snag — and you'd like to know without babysitting a log tail. Lert sends a push to your phone from any Ruby process with one HTTP POST. No gems to add, no API key to manage. This guide uses the standard-library Net::HTTP, wraps it in a reusable notify method, and drops it into a Rails job.

What you need

Only your Lert endpoint URL. Open the app and your unique URL is on screen — something like https://lert.dev/p/your-id. Tap Copy. Treat it like a password: anyone who has it can send you a notification, and you can regenerate it any time if it leaks. Everything below uses only Ruby's standard library — no bundle add required.

The basic POST with Net::HTTP

Net::HTTP ships with Ruby, so this runs anywhere Ruby does. Build a request, set the JSON body, send it, and check the status.

notify.rb
require "net/http"
require "json"
require "uri"

uri = URI("https://lert.dev/p/your-id")
req = Net::HTTP::Post.new(uri)
req["Content-Type"] = "application/json"
req.body = { title: "Import done", body: "3,412 rows in 47s", tag: "imports" }.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(req)
end

puts res.code == "200" ? "delivered" : "failed: #{res.code} #{res.body}"

A 200 comes back with {"delivered":1} and your phone is already buzzing. The use_ssl: true flag matters — Lert is HTTPS-only, and forgetting it is the most common reason a first attempt fails. All three fields are optional; send only a body, or nothing, and it still delivers.

A reusable notify method

You'll want this in more than one place, so wrap it. This notify method takes a body plus optional title and tag, reads the endpoint from an environment variable, and returns true on success without raising — so a failed notification never crashes the work that triggered it.

lert.rb
require "net/http"
require "json"
require "uri"

module Lert
  URL = ENV.fetch("LERT_URL", "https://lert.dev/p/your-id")

  def self.notify(body, title: nil, tag: nil)
    uri = URI(URL)
    payload = { title: title, body: body, tag: tag }.compact
    req = Net::HTTP::Post.new(uri)
    req["Content-Type"] = "application/json"
    req.body = payload.to_json

    res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: 5) do |http|
      http.request(req)
    end
    res.is_a?(Net::HTTPSuccess)
  rescue StandardError => e
    warn "Lert notify failed: #{e.message}"
    false
  end
end

# anywhere:
Lert.notify("Nightly report ready", title: "📊 Reports", tag: "cron")

Using .compact strips any nil fields, so you never send an empty title. The rescue catches network hiccups and returns false instead of blowing up — exactly what you want for a side-effect that isn't the point of the job. Point LERT_URL at your endpoint in the environment and the hard-coded fallback is only there for a quick test.

Already using an HTTP gem? If HTTParty or Faraday is in your Gemfile, a one-liner works too — HTTParty.post(url, body: payload.to_json, headers: {"Content-Type" => "application/json"}). Lert doesn't care which client you use; it only sees a plain POST.

Sending it from a Rails job

The natural home for a notification in Rails is a background job, so it runs off the request thread and retries if the network blips. Drop the Lert module above into app/lib and call it from an ActiveJob worker.

app/jobs/notify_job.rb
class NotifyJob < ApplicationJob
  queue_as :default

  def perform(order)
    Lert.notify(
      "#{order.item} · $#{order.total}",
      title: "💸 New sale",
      tag: "sales"
    )
  end
end

# from a controller or model callback:
NotifyJob.perform_later(order)

Now every completed order enqueues a job that buzzes your phone. Because it's a background job, a slow response or a momentary outage won't hold up the checkout, and your queue backend handles retries for you. See the new-sale notifications use case for more on wiring this to real orders.

Handling the response

Lert's responses are small and predictable. Match on the status code so your logs tell you what happened:

  • 200{"delivered":1}. The push is on its way.
  • 404{"error":"unknown endpoint"}. Your URL is wrong or was regenerated; copy it again from the app.
  • 429 — too many requests or the daily cap. Honor the Retry-After header before trying again. The limit is 60 requests/minute per IP, and 50 notifications/day on Free (unlimited on Pro, 10,000/day fair use).

Why Lert for Ruby notifications

Most notification tools want you to register an app, generate an API key, and add yet another gem before the first message ships. Lert removes all of it: the endpoint URL is the authentication, so notifying yourself is a plain Net::HTTP POST from code you already have. It's the shortest line between "my Ruby process did something" and "my phone knows."

FAQ

Do I need a gem to send a push from Ruby?

No. Net::HTTP is part of Ruby's standard library, so no gem is required. If you already use HTTParty or Faraday you can use those instead — all Lert needs is a plain HTTP POST.

Does this work inside a Rails background job?

Yes. Put the POST inside an ActiveJob or Sidekiq worker's perform method so the request runs off the web thread. It's a standard HTTP call, so nothing Rails-specific is needed.

How do I check whether it was delivered?

Check the response code. A 200 with body {"delivered":1} means success. A 404 means the endpoint is unknown, and a 429 means you hit a rate limit and should honor the Retry-After header.

Do I need an API key?

No. Your Lert endpoint URL is the authentication — there's no separate key, token, or login to wire up.

One POST from Ruby, one buzz on your phone.

Download Lert, copy your URL, and drop the Lert.notify module into any project.

Get the app iOS