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

glitchy-stripe

v2.0.1

Published

Glitchy affiliate network (gtrx.org) integration for Stripe — postback firing, cookie tracking, and deduplication helpers.

Readme

glitchy-stripe

Glitchy (gtrx.org) affiliate network integration for Stripe.

Handles the full postback flow: capturing click tokens on landing, forwarding them through the Stripe checkout session, and firing (deduplicated) conversion postbacks on first payment and every renewal.


Install

npm install glitchy-stripe

Environment variables

| Variable | Required | Description | |---|---|---| | GLITCHY_SECURITY_KEY | Yes | Your postback security token from the Glitchy network dashboard | | GLITCHY_OFFER_ID | No | Your offer ID — used for admin display and tracking link construction only, not sent in postbacks | | GLITCHY_POSTBACK_URL | No | Override the postback endpoint (default: https://glitchy.go2cloud.org/aff_lsr) |


Usage

1. Capture click tokens on landing

Add <GlitchyTracker /> to your root layout. It runs client-side, renders nothing, and writes the Glitchy click tokens into 30-day cookies on every page load.

// app/layout.tsx
import { GlitchyTracker } from "glitchy-stripe";

export default function RootLayout({ children }) {
    return (
        <html>
            <body>
                <GlitchyTracker />
                {children}
            </body>
        </html>
    );
}

2. Forward tokens through the Stripe checkout session

In your checkout API route, read the cookies and spread the metadata onto both the session and the subscription so renewal invoices also carry the click tokens.

// app/api/stripe/checkout/route.ts
import { getGlitchyMetadataFromCookies } from "glitchy-stripe";

const glitchyMeta = getGlitchyMetadataFromCookies(req.cookies);

await stripe.checkout.sessions.create({
    // ...
    metadata: { userId, plan, ...glitchyMeta },
    subscription_data: {
        metadata: { userId, plan, ...glitchyMeta },
    },
});

3. Fire the postback from your Stripe webhook

The Glitchy postback has no currency field — it always expects USD. Pass Stripe's raw amount_total and currency to convertSaleAmountToUSD and it handles everything: fetching live exchange rates, caching them for 1 hour, and dealing with zero-decimal currencies like JPY.

// app/api/stripe/webhook/route.ts
import {
    fireGlitchyPostback,
    convertSaleAmountToUSD,
    glitchyAlreadyReported,
    markGlitchyReported,
} from "glitchy-stripe";

async function reportToGlitchy(
    stripe: Stripe,
    invoiceId: string,
    amountTotal: number,
    currency: string,
    metadata: Record<string, string>,
) {
    const transactionId = metadata.glitchy_transaction_id ?? "";
    if (!transactionId) return; // organic sale, nothing to report

    if (await glitchyAlreadyReported(stripe, invoiceId)) return;

    const result = await fireGlitchyPostback({
        transactionId,
        saleAmount: await convertSaleAmountToUSD(amountTotal, currency),
        affiliateId: metadata.glitchy_sub1,
        offerId: metadata.glitchy_sub2,
        source: metadata.glitchy_sub4,
    });

    if (result.sent) await markGlitchyReported(stripe, invoiceId);
}


Exchange rates

convertSaleAmountToUSD fetches live rates from the free Frankfurter API (no key required) and caches them in memory for 1 hour. You don't need to set anything up — it just works. If the fetch fails, it uses the stale cache; if there's no cache yet, it returns "0.00" and logs an error.


How deduplication works

Stripe can deliver the same webhook event more than once. To prevent double-paying affiliates, markGlitchyReported stamps the Stripe invoice with glitchy_postback_sent: <ISO timestamp> after a successful postback. glitchyAlreadyReported always re-fetches the invoice from the Stripe API (not the webhook payload, which predates any marker we wrote) before firing.


API

convertSaleAmountToUSD(amountTotal, currency)

Converts a Stripe amount_total to a USD string for the postback. Async — fetches live rates from Frankfurter and caches for 1 hour.

| Param | Type | Description | |---|---|---| | amountTotal | number | Stripe's raw amount_total (smallest unit — cents for most, already in major units for zero-decimal currencies like JPY) | | currency | string | ISO 4217 code, case-insensitive ("gbp", "JPY", "usd") |

Returns a USD string to 2 decimal places (e.g. "22.85"), or "0.00" if no rate is available.

fireGlitchyPostback(input)

Fires the HTTP conversion postback. Never throws.

type GlitchyPostbackInput = {
    transactionId: string;   // Glitchy's click transaction id
    saleAmount: string;      // gross total in USD, e.g. "22.85"
    affiliateId?: string;    // logging only
    offerId?: string;        // logging only
    source?: string;         // logging only
    isTest?: boolean;        // tags logs as [TEST]
};

type GlitchyPostbackResult = {
    sent: boolean;
    skippedReason?: "no_transaction_id" | "missing_security_key" | "http_error" | "network_error";
    status?: number;
    responseBody?: string;
    url?: string; // security token redacted
};

GlitchyTracker

React client component. No props. Mount once in your root layout.

getGlitchyMetadataFromCookies(cookies)

Reads the gc_* cookies set by GlitchyTracker and returns a flat object safe to spread into Stripe metadata. Accepts any object with a .get(name) method (Next.js RequestCookies, NextRequest.cookies, or a plain Map).

glitchyAlreadyReported(stripe, invoiceId)

Returns true if the invoice has already been stamped. Pass your Stripe client instance.

markGlitchyReported(stripe, invoiceId)

Stamps the invoice. Call after a successful fireGlitchyPostback. Pass your Stripe client instance.

GLITCHY_OFFER_ID

The value of process.env.GLITCHY_OFFER_ID, or "" if unset.