Skip to content

What is Webring?

Posted on:December 5, 2025 at 12:00 PM

Webring

I created webring as a fun project to try to connect people sort of how it was done in the internet of old. Here’s how it works if you want to join:

  1. Register your website’s landing page at this link
  2. Add a “webring component” to your website. This would be some component that consists of a previous and next button, and grabs the previous and next site in the ring. The key for your place in the ring is the email address you registered with.
  3. You should be good to go! Thanks for giving it a try!
  4. To remove your site from the ring, simply unregister it at this link
import React, { useEffect, useState } from "react";
import { SITE } from "@config";

interface WebringLink {
  url: string;
  email: string;
}

const apiUrl = "https://webring-725549621836.us-central1.run.app/";
const email = SITE.email; // Your email address that you registered with

const Webring: React.FC = () => {
  const [prevSite, setPrevSite] = useState<WebringLink | null>(null);
  const [nextSite, setNextSite] = useState<WebringLink | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!apiUrl || !email) {
      setError("Webring not configured properly.");
      return;
    }

    const fetchLinks = async () => {
      try {
        const [prevRes, nextRes] = await Promise.all([
          fetch(`${apiUrl}/prev?cur=${encodeURIComponent(email)}`),
          fetch(`${apiUrl}/next?cur=${encodeURIComponent(email)}`),
        ]);

        if (prevRes.ok && nextRes.ok) {
          const prevJson = (await prevRes.json()) as WebringLink;
          const nextJson = (await nextRes.json()) as WebringLink;
          setPrevSite(prevJson);
          setNextSite(nextJson);
        } else {
          setError(`API responded with ${prevRes.status}`);
        }
      } catch (e) {
        const message =
          e instanceof Error ? e.message : "Failed to fetch webring";
        console.error("Webring fetch error:", message);
        setError(message);
      }
    };

    fetchLinks();
  }, []);

  if (error) {
    return (
      <div className="flex justify-center py-6">
        <p className="text-center text-xs text-gray-400">Webring: {error}</p>
      </div>
    );
  }

  if (!prevSite || !nextSite) return null;

  return (
    <div className="flex justify-center py-6">
      <div className="flex items-center gap-4">
        <a
          href={prevSite.url}
          className="text-sm font-medium"
          title={`Previous Site belongs to ${prevSite.email}`}
        >
          <span className="truncate">← Previous Site</span>
        </a>

        <a
          href="https://doshir.dev/posts/whatiswebring"
          className="text-xs"
        >
          Why Webring?
        </a>

        <a
          href={nextSite.url}
          className="text-sm font-medium"
          title={`Next Site belongs to ${nextSite.email}`}
        >
          <span className="truncate">Next Site →</span>
        </a>
      </div>
    </div>
  );
};

export default Webring;
← Previous SiteWhy Webring?Next Site →