Skip to content

microlinkhq/unavatar

Repository files navigation

logo

Table of Contents


Introduction

Welcome to unavatar.io, the ultimate avatar service that offers everything you need to easily retrieve user avatars:

It's proudly powered by microlink.io, the headless browser API that handles all the heavy lifting behind the scenes to ensure your avatars are always ready.

Quick start

The service is exposed in unavatar.io via provider endpoints:

Use /:provider/:key for provider-specific lookups, or pass an email as the only path segment for automatic resolution. You can read more in Email avatars and providers.

Authentication

Anonymous requests work without authentication. They are limited to 25 requests/day per IP address.

For PRO users, the requests must include the API key as the x-api-key request header:

curl "https://unavatar.io/github/kikobeats" -H "x-api-key: YOUR_API_KEY"
await fetch('https://unavatar.io/github/kikobeats', {
  headers: {
    'x-api-key': 'YOUR_API_KEY'
  }
})
import requests

response = requests.get(
  'https://unavatar.io/github/kikobeats',
  headers={'x-api-key': 'YOUR_API_KEY'}
)
package main

import "net/http"

func main() {
  req, _ := http.NewRequest("GET", "https://unavatar.io/github/kikobeats", nil)
  req.Header.Set("x-api-key", "YOUR_API_KEY")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()
}
require 'net/http'
require 'uri'

uri = URI('https://unavatar.io/github/kikobeats')
request = Net::HTTP::Get.new(uri)
request['x-api-key'] = 'YOUR_API_KEY'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
$ch = curl_init('https://unavatar.io/github/kikobeats');

curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'x-api-key: YOUR_API_KEY',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

If the API key is invalid, the service returns 401 with code EAPIKEY.

Rate limit status can be verified using these response headers:

Header Description
x-rate-limit-limit Maximum anonymous requests allowed in the current daily window
x-rate-limit-remaining Requests remaining in the current window
x-rate-limit-reset UTC epoch seconds when the current window resets
$ curl -I https://unavatar.io/github/kikobeats

x-rate-limit-limit: 25
x-rate-limit-remaining: 24
x-rate-limit-reset: 1744243200

Pricing

Unavatar pricing is simple: you can start on the anonymous free tier, then authenticate with x-api-key to get additional included usage and metered billing for higher volume.

Scenario Included free usage Billing
Anonymous (no API key) 25 requests/day per IP Free
Authenticated origin requests (x-api-key) 50 origin requests/day Metered monthly after free quota
Proxy requests (datacenter, residential) None Always metered

For higher usage, the PRO plan is usage-based billing that includes the 50 free daily origin requests, metered overage, and custom TTL.

Every request has a cost in tokens ($0.005 per token) based on the proxy tier needed to resolve the avatar:

Proxy tier Tokens Cost
Origin 1 $0.005
Datacenter +2 $0.015
Residential +4 $0.025

The proxy tier used is returned in the x-proxy-tier response header, and the total cost in the x-unavatar-cost header.

$ curl -I -H "x-api-key: YOUR_API_KEY" https://unavatar.io/instagram/kikobeats

x-pricing-tier: pro
x-proxy-tier: origin
x-unavatar-cost: 1

To upgrade, visit unavatar.io/checkout. After completing the payment, you'll receive an API key.

Cache

Unavatar caches avatar lookups to make repeated requests fast and stable:

  • The first request for a resource fetches the avatar from upstream and stores it in cache
  • Following requests are served from cache until the TTL expires.

For example, if you set ttl=1h, the cache behavior looks like this:

Time Request Cache status Plan impact
10:00 GET /github/kikobeats MISS (fetched from upstream) Counts as 1 origin request
10:05 GET /github/kikobeats HIT (served from cache) No usage consumed, no cost
10:40 GET /github/kikobeats HIT (served from cache) No usage consumed, no cost
11:02 GET /github/kikobeats MISS (TTL expired, cache refreshed) Counts as 1 origin request
11:10 GET /github/kikobeats HIT (served from cache) No usage consumed, no cost

To check the cache status in real requests, inspect these response headers:

Header What to look for
x-cache-status HIT means served from cache. MISS means fetched/refreshed from upstream.
cache-control Shows cache policy and effective TTL (for example public, max-age=3600 for ttl=1h).
$ curl -I -H "x-api-key: YOUR_API_KEY" "https://unavatar.io/github/kikobeats?ttl=1h"

cache-control: public, max-age=3600
x-cache-status: HIT

The same rule applies to anonymous requests: cache hits are free and do not consume the 25 requests/day limit.

After TTL expiration, the next request refreshes the cache and is billed/rate-limited according to the request tier (anonymous, origin, datacenter, or residential).

Query parameters

TTL

Type: number or string
Default: '24h'
Range: from '1h' to '28d'

It determines the maximum quantity of time an avatar is considered fresh.

e.g., unavatar.io/github/kikobeats?ttl=1h

When you look up for a user avatar for the very first time, the service will determine it and cache it respecting TTL value.

The same resource will continue to be used until reach TTL expiration. After that, the resource will be computed, and cache as fresh, starting the cycle.

Fallback

Type: string or boolean

When it can't be possible to get a user avatar, a fallback image is returned instead, and it can be personalized to fit better with your website or application style.

You can get one from boringavatars.com:

e.g., unavatar.io/github/37t?fallback=https://source.boringavatars.com/marble/120/1337_user?colors=264653r,2a9d8f,e9c46a,f4a261,e76f51

or avatar.vercel.sh:

e.g., unavatar.io/github/37t?fallback=https://avatar.vercel.sh/37t?size=400

or a static image:

e.g., unavatar.io/github/37t?fallback=https://avatars.githubusercontent.com/u/66378906?v=4

or even a base64 encoded image. This allows you to return a transparent, base64 encoded 1x1 pixel GIF, which can be useful when you want to use your own background colour or image as a fallback.

e.g., unavatar.io/github/37t?fallback=data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==

You can pass fallback=false to explicitly disable this behavior. In this case, a 404 Not Found HTTP status code will returned when is not possible to get the user avatar.

JSON

The service returns media content by default.

This makes the service easier to consume directly from HTML markup.

In case you want to get a JSON payload as response, just pass json=true:

e.g., unavatar.io/github/kikobeats?json

Providers

Apple Music

Get artwork for any Apple Music artist, album, or song. Search by name or look up directly by numeric Apple Music ID.

e.g., unavatar.io/apple-music/artist:daft%20punk

The endpoint supports explicit type as part of the input.

If explicit type is not provided, it searches artist and song (in that order).

Available URI format inputs:

Behance

Get any Behance user's profile picture by their username.

Available inputs:

Bluesky

Get any Bluesky user's profile picture by their handle. Domain-style handles are supported.

Available inputs:

DeviantArt

Get any DeviantArt user's profile picture by their username.

Available inputs:

Discord

Get a Discord server's icon by server name or server ID.

Available inputs:

Dribbble

Get any Dribbble designer's profile picture by their username.

Available inputs:

DuckDuckGo

Get the favicon or logo for any domain via DuckDuckGo's icon service. Useful as a fallback when a domain doesn't expose its favicon directly.

Available inputs:

Facebook

Get any Facebook user, page, or group profile picture by their username or ID.

Available inputs:

GitHub

Get any GitHub user or organization's profile picture by username, or resolve an avatar from a public email via GitHub search when the address matches a profile or commit history.

Available inputs:

GitLab

Get any GitLab user or organization's profile picture by their username.

Available inputs:

LinkedIn

Get any LinkedIn user or company profile picture by username or company slug.

e.g., unavatar.io/linkedin/user:wesbos

The input supports a URI format type:id.

When no type is provided, it defaults to user (user profile).

Available URI format inputs:

Google

Get the favicon or logo for any domain using Google's favicon service.

Available inputs:

Gravatar

Get any user's avatar by their email address via Gravatar. The most widely used global avatar service — if your users have a Gravatar set up, this is the fastest way to retrieve it.

Available inputs:

Instagram

Get any Instagram user's profile picture by their username. No authentication or API tokens needed — just pass the username.

Available inputs:

Ko-fi

Get any Ko-fi page's profile picture by the creator username.

Available inputs:

Medium

Get any Medium author's profile picture by their username.

Available inputs:

Microlink

Extract the logo or representative image from any URL. The page is rendered and the best available image is selected — useful for getting brand logos from any website.

Available inputs:

Mastodon

Get any Mastodon user's profile picture from any instance using the public account lookup API. Pass the handle as user@server so the account resolves on the correct home instance.

Available inputs:

OnlyFans

Get any OnlyFans creator's profile picture by their username.

Available inputs:

OpenStreetMap

Get any OpenStreetMap contributor's profile picture. Accepts either a numeric user ID or a username.

Available inputs:

Patreon

Get any Patreon creator's profile picture by their username.

Available inputs:

Pinterest

Get any Pinterest user's profile picture by their username.

Available inputs:

Printables

Get any Printables user's profile picture by their username.

Available inputs:

PSN Profiles

Get any PlayStation Network user's profile picture by their PSN username.

Available inputs:

Reddit

Get any Reddit user's avatar by their username.

Available inputs:

Snapchat

Get any Snapchat user's profile picture by their username.

Available inputs:

SoundCloud

Get any SoundCloud artist's profile picture by their username.

Available inputs:

Spotify

Get artwork for any Spotify entity — users, artists, albums, playlists, shows, episodes, or tracks. Look up by username or Spotify ID.

e.g., unavatar.io/spotify/album:7I9Wh2IgvI3Nnr8Z1ZSWby

The endpoint supports explicit type as part of the input.

If explicit type is not provided, it defaults to user.

Available URI format inputs:

Steam

Get any Steam player or community group profile picture by public profile name, numeric account ID, or group name.

e.g., unavatar.io/steam/id:gabelogannewell

The input supports a URI format type:value.

When no type is provided, it defaults to id (player profile name).

Available URI format inputs:

Substack

Get any Substack author's profile picture by their publication username.

Available inputs:

Telegram

Get any Telegram user's profile picture by their username.

Available inputs:

Threads

Get any Threads user's profile picture by their username.

Available inputs:

TikTok

Get any TikTok user's profile picture by their username. No authentication or API tokens needed — just pass the username.

Available inputs:

Tumblr

Get any Tumblr blog's profile picture by their username.

Available inputs:

Twitch

Get any Twitch streamer's profile picture by their username.

Available inputs:

Vimeo

Get any Vimeo user's profile picture by their username.

Available inputs:

WhatsApp

Get the profile picture for a WhatsApp channel or chat by ID.

e.g., unavatar.io/whatsapp/phone:34660021551

The input supports a URI format type:id.

If no type is provided, the input is treated as a phone number.

Available URI format inputs:

X/Twitter

Get any X (formerly Twitter) user's profile picture by their username.

Available inputs:

Xbox Gamertag

Get any Xbox player's profile picture by their gamertag.

Available inputs:

YouTube

Get any YouTube channel's thumbnail by their handle, legacy username, or channel ID.

e.g., unavatar.io/youtube/casey

The endpoint supports specific input formats.

If the input starts with UC and has 24 characters, it is treated as a channel ID. Otherwise, it is treated as a handle.

Available inputs:

Response Format

A response is returning the user avatar by default.

However, you can get a json as response payload.

When an endpoint returns JSON, the shape is predictable so you can parse it reliably in your app:

Field Type Present in Description
status string all JSON responses One of: success, fail, error.
message string all JSON responses Human-readable summary for display/logging.
data object success Response payload for successful requests.
code string fail, error Stable machine-readable error code.
more string (URL) most fail / error responses Documentation URL with troubleshooting details.
report string some error responses Support contact channel (for example mailto:).

Response Headers

These headers help you understand pricing, limits, and request diagnostics.

Header Purpose
x-pricing-tier free or pro — the plan used for this request
x-timestamp Server timestamp when request was received
x-unavatar-cost Token cost of the request (avatar routes only)
x-proxy-tier Proxy tier used: origin, datacenter, or residential
x-rate-limit-limit Maximum requests allowed per window (free tier only)
x-rate-limit-remaining Remaining requests in current window (free tier only)
x-rate-limit-reset UTC epoch seconds when window resets (free tier only)
retry-after Seconds until rate limit resets (only on 429 responses)
$ curl -I -H "x-api-key: YOUR_API_KEY" https://unavatar.io/github/kikobeats

x-pricing-tier: pro
x-timestamp: 1744209600
x-unavatar-cost: 1
x-proxy-tier: origin
x-rate-limit-limit: 50
x-rate-limit-remaining: 49
x-rate-limit-reset: 1744243200

Response Errors

Expected errors are known operational cases returned with stable codes.

  • Client-side issues return status: "fail" (HTTP 4xx).
  • Service-side issues return status: "error" (HTTP 5xx).
  • Unknown failures return EINTERNAL (HTTP 500).
  • Use the code for programmatic handling in clients.
  • Use the message to show user-facing feedback.
  • more links to documentation for common fixes.
  • report (when present) indicates how to contact support for server errors.
HTTP Code Typical trigger
400 ESESSIONID Missing session_id in /checkout/success
400 ESESSION Checkout session not paid or not found
400 ESIGNATURE Missing stripe-signature header
400 EWEBHOOK Invalid/failed Stripe webhook processing
400 EAPIKEYVALUE Missing apiKey query parameter
400 EAPIKEYLABEL Missing label query parameter
401 EEMAIL Invalid or missing authenticated email
401 EUSERUNAUTHORIZED Missing/invalid auth for protected routes
401 EAPIKEY Invalid x-api-key
403 ETTL Custom ttl requested without pro plan
403 EPRO Provider restricted to pro plan
404 ENOTFOUND Route not found
404 EAPIKEYNOTFOUND API key not found
409 EAPIKEYEXISTS Custom API key already exists
409 EAPIKEYLABELEXISTS API key label already exists
409 EAPIKEYMIN Attempt to remove last remaining key
429 ERATE Anonymous daily rate limit exceeded
500 ECHECKOUT Stripe checkout session creation failed
500 EAPIKEYFAILED API key retrieval after checkout failed
500 EINTERNAL Unexpected internal server failure

Contact

If you have any suggestion or bug to report, please contact to ust mailing to hello@unavatar.io.

About

Get unified user avatar from social networks, including Instagram, SoundCloud, Telegram, Twitter, YouTube & more.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors