avatarsniff
Sniff out generic default avatars, straight from the pixels.
A lot of users never set a profile picture, so providers serve a boring auto-generated default — an initial on a coloured square (Google), the Gravatar mystery-person, a solid placeholder. avatarsniff detects those from the image pixels so you can replace them with something better instead of showing the generic one. Decodes PNG/JPEG/GIF/WEBP/SVG up to 10MB, framework-agnostic, zero dependencies, server and client.
Install
Try it
These run entirely in your browser via detectFromImageData. The samples are drawn on a canvas and classified live — drop your own below.
Browser
import { detectFromImageData } from "avatarsniff";
const ctx = canvas.getContext("2d");
ctx.drawImage(avatarImg, 0, 0, 64, 64);
const { isDefault, reason } = detectFromImageData(
ctx.getImageData(0, 0, 64, 64)
);
if (isDefault) {
// generic provider default — swap in your own avatar
}Server (Node)
Batteries included and still zero-dependency (every decoder is bundled into the build): PNG, GIF and JPEG decode in pure JS on every runtime. For WEBP and SVG in plain Node, opt into a subpath — import "avatarsniff/webp" or import "avatarsniff/svg" — so their wasm only loads when you need it. Inputs over 10MB are rejected before decoding.
import { detectDefaultAvatar, detectDefaultAvatarFromUrl } from "avatarsniff";
// batteries included — decodes PNG/JPEG/GIF/WEBP/SVG, up to 10MB, zero deps
const result = await detectDefaultAvatar(bytes);
const fromUrl = await detectDefaultAvatarFromUrl(user.photoUrl);
// null if the URL is missing or the fetch failsHow it decides
It keys on structure, never a hard-coded palette (so it keeps working as providers add colours). An image is a default when the dominant background is a flat colour that is neither near-white nor near-black, there is a small near-white glyph (the initial), and there is almost no other coloured content.