npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

proofpin

v0.2.0

Published

Social proof popups with a live map of every visitor. Zero dependencies, one script tag.

Readme

📍 ProofPin

Social proof popups with a live map of every visitor.

Tiny corner popups that show real activity — and drop a pin on the visitor's city. Zero dependencies. One script tag. Bring your own brand.

npm license size no deps PRs welcome

🧭 Setup wizard · Quick start · Config


Most social-proof widgets show a boring avatar and a line of text. ProofPin drops a real map of the visitor's city behind an Apple-style pin — so "Sarah in Austin, TX just signed up" actually looks like it happened somewhere real. It reads as trustworthy because it is: ProofPin only ever shows the events you feed it.

┌───────────────────────────────────┐
│  ▓▓▓▓▓ │  Sarah in Austin, TX      │
│  ▓📍▓▓ │  Just started a free trial │
│  ▓▓▓▓▓ │  9 min ago · ✓ Verified   │
└───────────────────────────────────┘
     ▲ live map tile of their city

Why ProofPin

  • 🗺️ The map is the hook — a live, keyless map tile centered on each visitor's city.
  • 🪶 Zero dependencies — ~6kb gzipped, no framework, works on any site (HTML, WordPress, Shopify, React…).
  • 🎨 Your brand in minutes — logo, colors, pin, position, and copy are all config.
  • 🔌 Bring your own data — a static array, your own endpoint, or the included one-click backend.
  • 🔒 Honest by design — it shows only the real events you give it. No fake-event generator here (see Honest proof).
  • 🔔 5 notification types — visitor events (with the map), live count, announcements, countdown timers, and reviews.

ProofPin vs the paid tools

| | ProofPin | Provely | Fomo | typical $29/mo tool | | --- | :---: | :---: | :---: | :---: | | Price | Free, MIT | ~$17–95/mo | ~$19–99/mo | ~$29/mo | | Live map of the visitor's city | ✅ | ❌ | ❌ | ❌ | | Zero dependencies, one script tag | ✅ | ❌ | ❌ | ❌ | | Self-hosted / your data | ✅ | ❌ | ❌ | ❌ | | Visitor events + live count | ✅ | ✅ | ✅ | ✅ | | Announcements / timers / reviews | ✅ | ✅ | ✅ | ✅ | | Fabricated "past data" mode | ✅ never | ✅ (a feature) | ⚠️ | ⚠️ | | Open source | ✅ | ❌ | ❌ | ❌ |

Same core features as the tools charging monthly — plus a live map they don't have, and no subscription.

🧭 Setup wizard (easiest)

→ Open the setup wizard — answer a few questions, watch the live preview, and copy a snippet that's already filled in with your brand, colors, and data source. No code to write.

Quick start (manual)

Drop in one script tag and initialize. This CDN link works today — no npm install needed:

<script src="https://cdn.jsdelivr.net/npm/proofpin"></script>
<script>
  ProofPin.init({
    logo: '/logo.svg',
    brandName: 'Acme',
    defaultAction: 'Just started a free trial',
    events: [
      { name: 'Sarah', place: 'Austin, TX', lat: 30.27, lon: -97.74, time: Date.now() - 540000 },
      { name: 'Marcus', place: 'Miami, FL', lat: 25.76, lon: -80.19, time: Date.now() - 120000 },
    ],
  })
</script>

That's the whole thing. No build step, no account. Paste it just before </body>.

Using a bundler instead? Install from npm:

npm install proofpin

Prefer no inline JS? Add a data-proofpin attribute with a JSON config to the script tag and ProofPin auto-initializes.

Where the data comes from

ProofPin renders whatever you give it. Pick one:

1. A static array — great for testimonials, demos, or when your backend already pushes events somewhere:

ProofPin.init({ events: [ /* {name, place, lat, lon, time, text} */ ] })

2. Your own endpoint — ProofPin GETs it and expects { events: [...], viewsToday: 0 }:

ProofPin.init({ endpoint: '/api/proof' })

3. The included backend (one click) — a Netlify Function + Netlify Blobs that captures real events, derives the city + map coordinates from the visitor's IP (server-side, never asked for), and counts a rolling 24h "viewing" number:

Deploy to Netlify

Then, from your app, record a real event whenever something real happens:

// after a genuine signup / purchase / booking:
fetch('/.netlify/functions/proofpin', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ type: 'event', name: 'Sarah', text: 'Just started a free trial' }),
})

…and point the widget at it: ProofPin.init({ endpoint: '/.netlify/functions/proofpin' }).

Notification types

Besides visitor events, pass extra cards via cards: [...]. They're mixed into the rotation.

ProofPin.init({
  events: [ /* visitor events with the map */ ],
  cards: [
    { kind: 'announcement', title: 'New: v2 is live', text: 'Ship faster today',
      cta: 'Learn more', url: 'https://yoursite.com/v2' },
    { kind: 'timer', title: 'Launch ends in', until: Date.now() + 2*60*60*1000 },
    { kind: 'review', rating: 5, quote: 'Best tool we added all year.', name: 'Mia', place: 'NYC' },
  ],
})
  • announcementtitle, text, optional cta + url
  • timertitle, until (epoch ms); counts down live
  • reviewquote, rating (1–5), optional name, place
  • event — the visitor card (name, place, lat, lon, text, url)
  • count — the live "X people viewing" card (from viewsToday)

Any card with a url (or a global onClick) becomes clickable.

Push events live

Fire a notification the moment something real happens — no reload:

ProofPin.init({ /* ... */ })
// later, e.g. inside your signup success handler:
ProofPin.push({ name: 'Sarah', place: 'Austin, TX', lat: 30.27, lon: -97.74, text: 'Just signed up' })
// or any card type:
ProofPin.push({ kind: 'review', rating: 5, quote: 'Love it!', name: 'Dev' })

Configuration

Every option, with defaults:

| Option | Default | What it does | | --- | --- | --- | | endpoint | null | URL to GET events from ({ events, viewsToday }). | | events | null | Static array of events instead of an endpoint. | | viewsToday | 0 | Count to use with a static events array. | | recordViews | true | POST {type:'view'} to the endpoint on load. | | position | 'bottom-left' | bottom-left, bottom-right, top-left, or top-right. | | cards | null | Extra cards (announcement / timer / review) mixed into the rotation. | | onClick | null | fn(item) fired when a card is clicked. | | maxDisplays | 0 | Stop after N cards per session (0 = unlimited). | | showOnMobile | true | false hides the widget on screens under 640px. | | pages | null | Only show on matching paths, e.g. ['/pricing','/blog/*'] (null = everywhere). | | gradient | ['#7D4AFE','#4399EC','#07EBDB'] | Brand accent gradient. | | accent | '#4399EC' | "Verified by" / accent color. | | pinColor | '#FF3B30' | The map drop pin. | | dark | true | Dark glass card (false = light card). | | logo | null | Small logo URL for the "Verified by" badge. | | brandName | 'us' | Shown as "Verified by {brandName}" when no logo. | | verifiedText | 'Verified by' | Label before the logo/brand. | | showVerified | true | Show the verified badge line. | | showMap | true | Show the map panel (falls back to gradient + pin). | | mapZoom | 12 | Map zoom (higher = tighter on streets). | | defaultAction | 'Just signed up' | Action line; per-event text overrides it. | | countText | '{n} people viewing recently' | Headline for the count card ({n} = viewsToday). | | countSubtext | 'in the last 24 hours' | Sub-line for the count card. | | viewFloor | 8 | Hide the count card below this number. | | maxAgeHours | 48 | Ignore events older than this. | | firstDelay | 5000 | Delay (ms) before the first popup. | | visibleMs | 6500 | How long each popup stays (ms). | | gapMs | 2800 | Gap between popups (ms). | | dismissible | true | Show the ✕ dismiss button. | | respectReducedMotion | true | Honor prefers-reduced-motion. | | zIndex | 2147483000 | Stacking order. |

Event shape

{
  name: 'Sarah',        // first name (kept short)
  place: 'Austin, TX',  // shown next to the name
  lat: 30.27,           // optional — enables the map tile
  lon: -97.74,          // optional
  time: 1700000000000,  // epoch ms (or `t`)
  text: 'Just signed up' // optional per-event action line
}

No lat/lon? The card gracefully falls back to your brand gradient with the pin.

API

const pin = ProofPin.init(config) // start
pin.push(item)                    // add a card/event live (see "Push events live")
pin.dismiss()                     // stop and hide
pin.destroy()                     // remove entirely
ProofPin.push(item)               // push to the most recent instance
ProofPin.version                  // e.g. "0.2.0"

Honest proof

ProofPin ships without a fake-event generator, on purpose. Invented social proof ("Someone just bought!" when nobody did) is deceptive and, in many places, illegal (e.g. the US FTC's rules on fake endorsements). ProofPin only renders the events you feed it — so feed it real ones, fired from real signups, purchases, or bookings. Honest proof converts and keeps you out of trouble. This tool just makes it look great.

The map

Map tiles come from CARTO Voyager basemaps (no API key needed for light use). Attribution for OpenStreetMap and CARTO is required if you display the map — add a small line in your footer:

Maps © OpenStreetMap contributors, © CARTO

Higher traffic? Swap the one TILE constant in src/proofpin.js for a keyed provider (Mapbox, MapTiler, etc.).

Browser support

All modern browsers (Chrome, Safari, Firefox, Edge). Uses fetch and backdrop-filter; degrades gracefully where backdrop-filter is unsupported.

Development

npm install       # dev deps (esbuild, @netlify/blobs)
npm run build     # -> dist/proofpin.min.js (+ copies into demo/)

Open docs/index.html to run the setup wizard locally.

Contributing

Issues and PRs welcome. Keep it dependency-free and small.

License

MIT © Jay Awal (@mr.jayawal)