233 words, 2 min read

Gravatar is a widely used service for associating profile images with email addresses. If your application doesn't store avatars locally, Gravatar offers a reliable fallback based on the user's email hash. Here's a minimal and idiomatic Elixir module to generate Gravatar URLs.

The helper module

defmodule AvatarHelper do
@moduledoc """
Generates a Gravatar URL based on a user's email.
"""
@gravatar_base_url "https://secure.gravatar.com/avatar"
@default_gravatar_id "00000000000000000000000000000000"
@doc """
Returns the Gravatar URL for the given object.
## Options
* `:size` – image size in pixels (default: 180)
* `:default` – default Gravatar image type if email is missing (default: `"mp"`)
## Examples
iex> AvatarHelper.avatar_url(%{email: "user@example.com"})
"https://secure.gravatar.com/avatar/23463b99b62a72f26ed677cc556c44e8?s=180&d=mp"
"""
def avatar_url(object, opts \\ []) do
size = Keyword.get(opts, :size, 180)
default_image = Keyword.get(opts, :default, "mp")
params = "?s=#{size}&d=#{default_image}"
gravatar_id =
case Map.get(object, :email) do
email when is_binary(email) and email != "" -> md5_hash(email)
_ -> @default_gravatar_id
end
"#{@gravatar_base_url}/#{gravatar_id}#{params}"
end
defp md5_hash(email) do
email
|> String.downcase()
|> then(&:crypto.hash(:md5, &1))
|> Base.encode16(case: :lower)
end
end

Why this approach?

  • No local storage checks – It’s purely Gravatar-based.
  • Fallback behavior – If no valid email is present, it uses a default blank hash.
  • Customizable – You can pass options like size (:size) and default image type (:default), such as "identicon", "retro", or "mp".

Usage in Phoenix

Use this in a template or LiveView like this:

<img src={AvatarHelper.avatar_path(@user)} alt="User avatar" />

This keeps your app simple and your user avatars globally consistent.