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

astro-tinylytics

v0.1.0

Published

Astro components for Tinylytics analytics, kudos buttons, and webmentions.

Readme

astro-tinylytics

Astro components for Tinylytics — analytics, kudos, webmentions, event tracking, webrings, and the no-JS tracking pixel.

Install

pnpm add astro-tinylytics

Astro >=4.0.0 is a peer dependency.

Quickstart

Drop the script into your site <head> and place widgets where you want them:

---
import { Script, Hits, Kudos, Uptime, Countries, Webring } from "astro-tinylytics";
---
<head>
  <Script
    embedCode="YOUR_EMBED_CODE"
    hits
    kudos="custom"
    events
    beacon
    uptime
    countries
    webring="avatars"
  />
</head>

<p>Total visits: <Hits /></p>
<Kudos path="/posts/hello" />
<Uptime /> uptime
<Countries />
<Webring avatar>Random indie site</Webring>

Components

<Script>

Renders the Tinylytics embed <script> with typed props for every documented URL flag. Enable each widget / feature with a boolean prop; the component produces the matching query string.

<Script embedCode="YOUR_EMBED_CODE" hits kudos="custom" events beacon />
<!-- → <script src="https://tinylytics.app/embed/YOUR_EMBED_CODE.js?hits&kudos=custom&events&beacon" defer></script> -->

| Prop | Type | Default | Notes | | ----------- | ---------------------------------- | ------- | ----------------------------------------------------------------------------- | | embedCode | string | — | Required. Your site's Tinylytics embed code. | | min | boolean | false | Load the minified min.js build. | | spa | boolean | false | Enable client-routed SPA mode. | | ignore | boolean | false | Load the script but suppress tracking on this page. | | hits | boolean \| "unique" | — | true?hits, "unique"?hits=unique. | | kudos | boolean \| "custom" \| string | — | true?kudos, "custom"?kudos=custom, or any custom emoji/string. | | uptime | boolean | false | Enable the uptime widget (paid plan). | | countries | boolean | false | Enable the visitor-countries widget. | | webring | boolean \| "avatars" | — | true?webring, "avatars"?webring=avatars. | | events | boolean | false | Enable event tracking (required for <Event>). | | beacon | boolean | false | Use sendBeacon so link-click events aren't dropped during navigation. | | defer | boolean | true | Emit defer on the script tag. |

<Hits>, <Countries>, <Uptime>

Widget elements the Tinylytics script scans for. Each renders an empty <span> by default — the script fills in the content on load.

<Hits />                          <!-- lifetime hit counter -->
<Countries as="div" class="flags" />
<Uptime class="badge" />

| Prop | Type | Default | Notes | | -------- | ---------------------------- | -------- | ----------------------------------------------------------- | | as | keyof HTMLElementTagNameMap| "span" | Override the tag. | | class | string | — | Extra class names (merged with the Tinylytics class hook). | | ignore | boolean | false | Set data-ignore="true" to exclude this instance. |

<Kudos>

A low-level kudos button. Leave the slot empty to let Tinylytics inject its default 👋 N content, or provide your own markup (useful with kudos="custom" on <Script>).

<Kudos path="/posts/hello" />
<Kudos path="/posts/hello">❤️ Love it</Kudos>

| Prop | Type | Default | Notes | | --------- | --------- | ------------- | -------------------------------------------------------------------- | | path | string | current URL | Pin kudos to a canonical path. Required when multiple buttons share a page. | | private | boolean | false | Count visible only to the site owner. | | ignore | boolean | false | Set data-ignore="true". | | class | string | — | Extra class names. |

For a higher-level button with icon, label, count threshold, and suffix template, see <KudosButton>.

<Webring>

Renders the webring anchor Tinylytics fills with a random ring member on page load. Requires <Script webring /> (or webring="avatars" if avatar is used).

<Webring>Random indie site</Webring>

<Webring avatar avatarPosition="before" avatarAlt="Current ring member">
  Visit next
</Webring>

| Prop | Type | Default | Notes | | ---------------- | ----------------------- | ---------- | ------------------------------------------------------------------------------------ | | avatar | boolean | false | Render the avatar <img>. Script must be loaded with webring="avatars". | | avatarPosition | "before" \| "after" | "before" | Avatar placement relative to the slot. | | avatarAlt | string | "" | Avatar alt text. Empty string renders aria-hidden="true". | | newTab | boolean | true | Open in a new tab (target="_blank" rel="noopener"). | | class | string | — | Extra class names. |

<Event>

Wraps any element with Tinylytics event-tracking data attributes. Auto-renders as <a> when href is present, otherwise <button>. Pass as to force a tag. Extra HTML attributes forward to the rendered element.

Requires <Script events /> (plus beacon if the event navigates away, e.g. an external link or download).

<Event name="file.download" value="resume.pdf" as="a" href="/resume.pdf">
  Download resume
</Event>

<Event name="nav.menu.open">Menu</Event>

Event names use Tinylytics' category.action format.

| Prop | Type | Notes | | ------- | ----------------------------------------- | ---------------------------------------------------- | | name | string | Required. The event name. | | value | string | Optional. Stored as event_properties["value"]. | | as | "a" \| "button" \| "div" \| "span" | Override the inferred tag. |

<Pixel>

Renders a 1×1 tracking image for RSS feeds, HTML email, and other no-JavaScript contexts. A hit is registered when the image is fetched.

<Pixel embedCode="YOUR_EMBED_CODE" path="/posts/hello" />

| Prop | Type | Notes | | ----------- | -------- | ---------------------------------------------------------------------------------- | | embedCode | string | Required. | | path | string | Optional. Path to attribute the hit to. A leading / is added if missing. |

<KudosButton>

Opinionated wrapper around <Kudos> with a configurable icon, label, count threshold, and suffix template that reveals a "— and so do N others" phrase once the count exceeds the threshold.

---
import { KudosButton } from "astro-tinylytics";
import "astro-tinylytics/styles.css"; // optional: opt-in default styles
---
<KudosButton path="/my-article-slug" />

Customize:

<KudosButton
  path="/my-article-slug"
  label="Leave a kudo"
  icon="❤️"
  countThreshold={5}
  suffixTemplate="— loved by {count} readers"
  as="span"
  class="my-wrapper-class"
/>

| Prop | Type | Default | Notes | | ---------------- | ------------------- | ------------------------------ | --------------------------------------------------------------------- | | path | string | — | Required. Pins kudos to a canonical path. | | label | string | "I like this" | Rendered as a text label and the button's aria-label. | | countThreshold | number | 10 | The suffix is hidden unless the count is strictly greater. | | suffixTemplate | string | "— and so do {count} others" | {count} is replaced with the live count. | | icon | string | "🚀" | Rendered via a CSS ::before pseudo-element. | | as | "div" \| "span" | "div" | Wrapper element. | | class | string | — | Extra class applied to the wrapper. |

Requires the Tinylytics script to be loaded with kudos="custom", which makes the embed inject only the count (a number) into the button. A small observer in the component strips the count out of the button and renders it into the suffix once it clears the threshold.

<Tinylytics> (convenience wrapper)

Higher-level wrapper for the common "analytics OR webmention endpoint" setup. Renders either the embed <script> (with optional kudos / hits flags) or the <link rel="webmention"> — they're typed as mutually exclusive, so call it twice if you need both. For finer control (uptime, countries, events, etc.), use <Script> directly.

Imported via subpath (not the barrel):

---
import Tinylytics from "astro-tinylytics/Tinylytics.astro";
---
<head>
  <Tinylytics embedCode="YOUR_EMBED_CODE" webmention />
  <Tinylytics embedCode="YOUR_EMBED_CODE" kudos="custom" hits />
</head>

| Prop | Type | Default | Notes | | ------------ | ------------------------- | ------- | ------------------------------------------------------------------ | | embedCode | string | — | Required. | | kudos | boolean \| "custom" | false | true?kudos, "custom"?kudos=custom. | | hits | boolean \| "unique" | false | true?hits, "unique"?hits=unique. | | webmention | true | — | Mutually exclusive with kudos / hits. |

URL helpers

For consumers that build Tinylytics URLs directly (e.g. for feed generation):

import { buildScriptUrl, buildPixelUrl } from "astro-tinylytics";

buildScriptUrl({ embedCode: "abc", hits: true, kudos: "custom" });
// → "https://tinylytics.app/embed/abc.js?hits&kudos=custom"

buildPixelUrl("abc", "/posts/hello");
// → "https://tinylytics.app/pixel/abc.gif?path=%2Fposts%2Fhello"

Theming <KudosButton>

Importing styles.css opts into the default look. Override any of these CSS variables at a higher scope to restyle without rewriting the ruleset:

| Variable | Default | | -------------------------- | ------------------------ | | --tlt-kudos-fg | inherit | | --tlt-kudos-bg | transparent | | --tlt-kudos-border | 1px solid currentColor | | --tlt-kudos-radius | 4px | | --tlt-kudos-padding | 4px 10px | | --tlt-kudos-icon | "🚀" | | --tlt-kudos-hover-bg | currentColor | | --tlt-kudos-hover-fg | white | | --tlt-kudos-hover-border | currentColor | | --tlt-kudos-muted | inherit |

The icon prop writes --tlt-kudos-icon as an inline style on each button, so per-instance icons override the global value.

Skip styles.css entirely and style the class hooks yourself if you want full control:

  • .tinylytics-kudos-wrapper — the outer element
  • .tinylytics-kudos-label — the text label
  • .tinylytics_kudos — the button (the class the Tinylytics embed script looks for)
  • .tinylytics-kudos-suffix — the "and so do N others" container (set hidden below the threshold)
  • .tinylytics-kudos-count — the count span inside the suffix

Starlight

Starlight supports <head> overrides via component slots. Create a Head.astro:

---
// src/components/Head.astro
import Default from "@astrojs/starlight/components/Head.astro";
import { Script } from "astro-tinylytics";

const embedCode = import.meta.env.PUBLIC_TINYLYTICS;
---
<Default><slot /></Default>
<link rel="webmention" href={`https://tinylytics.app/webmention/${embedCode}`} />
<Script embedCode={embedCode} hits kudos="custom" events beacon />

Then register it in astro.config.ts:

starlight({
  components: {
    Head: "./src/components/Head.astro",
  },
});

License

MIT