Skip to main content
doc0blade47/dubdocumentation home
Sign in

Admin Dashboard

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The admin dashboard provides a centralized management and moderation portal for Dub administrators and enterprise staff. It operates as an internal interface hosted under the admin.dub.co domain, restricted to authorized users belonging to the core Dub workspace. By integrating role-based access guards, session impersonation tools, global link and workspace controls, partner oversight workflows, and custom registrar management tools, the dashboard equips operators with the capabilities needed to supervise platform traffic, review affiliate applications, and handle security incidents.

Sources: apps/web/lib/auth/admin.ts:22-39, apps/web/lib/middleware/admin.ts:8-37

Admin Authentication and Role Guards

Role Verification and Workspace Validation

Dub implements a multi-layered security model to verify internal administrative roles, enforce route guards across edge middleware and API endpoints, and filter UI navigation tabs based on user-specific access rules.

The administrative access architecture relies on membership within the primary Dub workspace (DUB_WORKSPACE_ID). The function getDubAdminRole queries prisma.projectUsers using the user ID and the fixed workspace identifier to retrieve the user's assigned WorkspaceRole.

export const getDubAdminRole = async (userId: string) => {
  const response = await prisma.projectUsers.findUnique({
    where: {
      userId_projectId: {
        userId,
        projectId: DUB_WORKSPACE_ID,
      },
    },
    select: {
      role: true,
    },
  });
 
  if (!response) {
    return null;
  }
  return response.role;
};

Sources: apps/web/lib/auth/admin.ts:22-39

API routes intended for administrative use are wrapped with the withAdmin higher-order function. This handler enforces a strict sequence of checks before executing the underlying controller logic:

  1. Validates that an active session and user object exist, returning a 401 Unauthorized response otherwise.
  2. Resolves the user's admin role via getDubAdminRole; if no role is found, it returns a 401 Unauthorized response.
  3. If requiredRoles are specified, it verifies that the user's role is included in the permitted list, returning a 403 Forbidden response if validation fails.
  4. Validates API path access using canAccessAdminApiPath.
export const withAdmin =
  (
    handler: WithAdminHandler,
    { requiredRoles = [] }: { requiredRoles?: WorkspaceRole[] } = {},
  ) =>
  async (
    req: Request,
    { params: initialParams }: { params: Promise<Record<string, string>> },
  ) => {
    const params = (await initialParams) || {};
    const session = await getSession();
    if (!session?.user) {
      return new Response("Unauthorized: Login required.", { status: 401 });
    }
 
    const adminRole = await getDubAdminRole(session.user.id);
    if (!adminRole) {
      return new Response("Unauthorized: Not an admin.", { status: 401 });
    }
 
    if (requiredRoles.length > 0 && !requiredRoles.includes(adminRole)) {
      return new Response(
        `Unauthorized: Missing required admin role(s): ${requiredRoles.join(", ")}.`,
        { status: 403 },
      );
    }
 
    if (
      !canAccessAdminApiPath({
        userId: session.user.id,
        pathname: new URL(req.url).pathname,
      })
    ) {
      return new Response("Unauthorized: You don't have access to this page.", {
        status: 403,
      });
    }
 

Sources: apps/web/lib/auth/admin.ts:41-78

Important

Administrative API endpoints check both workspace project membership and path-specific blocklists. A valid workspace role alone does not grant access to restricted API paths if the user's identifier appears in the admin access blocklist.

Edge Middleware Guards

Incoming requests to the admin.dub.co domain are intercepted by AdminMiddleware. The middleware inspects the user token, checks project membership against DUB_WORKSPACE_ID using prismaEdge.projectUsers.findUnique, and enforces navigation rules before rewriting or redirecting the request.

export async function AdminMiddleware(req: NextRequest) {
  const { path } = parse(req);
 
  const user = await getUserViaToken(req);
 
  if (!user && path !== "/login") {
    return NextResponse.redirect(new URL("/login", req.url));
  } else if (user) {
    const isAdminUser = await prismaEdge.projectUsers.findUnique({
      where: {
        userId_projectId: {
          userId: user.id,
          projectId: DUB_WORKSPACE_ID,
        },
      },
    });
 
    if (!isAdminUser) {
      return NextResponse.next(); // throw 404 page
    } else if (
      path === "/login" ||
      !canAccessAdminPath({ userId: user.id, pathname: path })
    ) {
      return NextResponse.redirect(new URL("/", req.url));
    }
  }
 
  return NextResponse.rewrite(
    new URL(`/admin.dub.co${path === "/" ? "" : path}`, req.url),
  );

Sources: apps/web/lib/middleware/admin.ts:8-37

Access Blocklists and Restricted Paths

Certain administrative user IDs can be restricted from accessing specific sensitive dashboard sections and API namespaces through ADMIN_ACCESS_BLOCKLIST.

Guard ConstantValue / Path ArrayPurpose
ADMIN_ACCESS_BLOCKLIST["user_1M3YFDDQ97AGTKWQ9NCSRQTYB"]Identifies user IDs excluded from restricted administrative paths.
ADMIN_RESTRICTED_PATHS["/links", "/revenue", "/domains"]Dashboard frontend paths blocked for blocklisted users.
ADMIN_RESTRICTED_API_PATHS["/api/admin/links", "/api/admin/workspaces", "/api/admin/revenue", "/api/admin/domains"]API routes blocked for blocklisted users.

Sources: apps/web/lib/auth/admin-access-guard.ts:3-14

Path matching is handled by canAccessAdminPath and canAccessAdminApiPath, which evaluate whether a given pathname matches or starts with any entry in the restricted path arrays for blocklisted users.

const matchesPath = (pathname: string, paths: string[]) =>
  paths.some((p) => pathname === p || pathname.startsWith(`${p}/`));
 
export const isAdminAccessRestricted = (userId?: string | null): boolean =>
  !!userId && ADMIN_ACCESS_BLOCKLIST.includes(userId);
 
export const canAccessAdminPath = ({
  userId,
  pathname,
}: {
  userId?: string | null;
  pathname: string;
}): boolean =>
  !isAdminAccessRestricted(userId) ||
  !matchesPath(pathname, ADMIN_RESTRICTED_PATHS);
 
export const canAccessAdminApiPath = ({
  userId,
  pathname,
}: {
  userId?: string | null;
  pathname: string;
}): boolean =>
  !isAdminAccessRestricted(userId) ||
  !matchesPath(pathname, ADMIN_RESTRICTED_API_PATHS);

Sources: apps/web/lib/auth/admin-access-guard.ts:16-40

UI Navigation Filtering

The admin dashboard layout client utilizes session state and canAccessAdminPath to dynamically filter navigation tabs rendered in AdminNav. Tabs such as links, revenue, and domains are hidden or omitted for users subject to access restrictions.

const visibleTabs = useMemo(
  () =>
    status === "loading"
      ? []
      : tabs.filter((tab) =>
          canAccessAdminPath({
            userId: session?.user?.id,
            pathname: tab.href,
          }),
        ),
  [status, session?.user?.id],
);

Sources: apps/web/app/ee/admin.dub.co/dashboard/layout-nav-client.tsx:57-68

User Impersonation Flow

Identifier Parsing and Query Resolution

The user impersonation system allows administrators to look up accounts by email, workspace slug, custom domain, or Stripe customer ID, view linked projects and partner metrics, and generate secure impersonation links. The client interface handles input parsing, clipboard paste normalization, and user ban actions.

export function ImpersonateUser() {
  const [data, setData] = useState<UserInfoProps | null>(null);
  const [blockEmailDomain, setBlockEmailDomain] = useState(false);
 
  return (
    <div className="flex flex-col space-y-5">
      <form
        action={async (formData) => {
          await fetch("/api/admin/impersonate", {
            method: "POST",
            body: JSON.stringify({
              query: formData.get("query"),
            }),
          }).then(async (res) => {
            if (res.ok) {
              setBlockEmailDomain(false);
              setData(await res.json());
            } else {
              const error = await res.text();
              toast.error(error);
            }
          });
        }}
      >
        <Form />
      </form>
      {data ? (
        <form
          action={async () => {
            const emailDomain = data.email.split("@")[1];
            const blockDomainMessage = blockEmailDomain
              ? ` and block signups from @${emailDomain}`
              : "";
 
            if (
              !confirm(
                `This will ban the user ${data.email} and delete all their workspaces and links${blockDomainMessage}. Are you sure?`,
              )
            ) {
              return;
            }
            await fetch("/api/admin/ban", {
              method: "POST",
              body: JSON.stringify({
                email: data.email,
                blockEmailDomain,
              }),
            }).then(async (res) => {
              if (res.ok) {
                toast.success("User has been banned");
              } else {
                const error = await res.text();
                toast.error(error);
              }
            });
          }}
        >
          <UserInfo data={data} />
          <label className="mt-4 flex cursor-pointer items-center gap-2 text-sm text-neutral-600">
            <input
              type="checkbox"
              checked={blockEmailDomain}
              onChange={(e) => setBlockEmailDomain(e.target.checked)}
              className="rounded border-neutral-300 text-neutral-900 focus:ring-neutral-500"
            />
            Also block signups from @{data.email.split("@")[1]}
          </label>
          <div className="mt-4">
            <BanButton />
          </div>
        </form>
      ) : (
        <UserInfoSkeleton />
      )}
    </div>
  );
}

Sources: apps/web/app/ee/admin.dub.co/dashboard/components/impersonate-user.tsx:10-86

When an administrator inputs a search query into the form, clipboard paste events are intercepted to clean prefixes such as mailto: and extract Stripe customer identifiers matching cus_[a-zA-Z0-9]+. The backend API processes this input through parseImpersonateQuery to categorize the target into one of four specific identifier types.

Identifier TypeMatching Pattern / ConditionResolution Rule
emailContains @Validated against emailSchema using Zod.
stripeCustomerIdStarts with cus_ or contains stripe.comMatched using STRIPE_CUSTOMER_ID_REGEX.
slugHostname matches app domain with a valid path segment, or raw input matches validSlugRegexLowercased and checked against slug regex.
domainNormalized input matches validDomainRegexNormalized via normalizeDomainInput.

Sources: apps/web/app/ee/api/admin/impersonate/route.ts:105-180, apps/web/app/ee/admin.dub.co/dashboard/components/impersonate-user.tsx:104-118

Note

If a query string contains a URL pointing to the primary application hostname, the parser extracts the first path segment as a workspace slug, provided it satisfies validSlugRegex. Otherwise, it falls back to domain or slug validation on the raw string.

Usage Metrics and Serialization

Once a user is located, their associated projects and partner configurations are serialized. Projects are selected with fields including plan tiers, trial expiration dates, partner usage statistics, total clicks, total links, and associated programs. If a user belongs to two or fewer projects, the system queries the last 30 days of workspace statistics using getLast30DayWorkspaceStats. Additionally, program commissions are grouped and aggregated by programId.

const userSelect = {
  email: true,
  projects: {
    select: {
      project: {
        select: {
          id: true,
          name: true,
          slug: true,
          plan: true,
          planPeriod: true,
          trialEndsAt: true,
          defaultProgramId: true,
          partnersUsage: true,
          totalClicks: true,
          totalLinks: true,
          programs: {
            select: {
              id: true,
              slug: true,
              url: true,
            },
          },
        },
      },
    },
    orderBy: {
      project: {
        totalClicks: "desc",
      },
    },
  },
  partners: {
    select: {
      partner: {
        select: {
          programs: {
            select: {
              program: {
                select: {
                  id: true,
                  name: true,
                  slug: true,
                },
              },
              status: true,
              totalClicks: true,
              totalLeads: true,
              totalConversions: true,
              totalSaleAmount: true,
              totalCommissions: true,
            },
            orderBy: {
              totalCommissions: "desc",
            },
          },
        },
      },
    },
  },
} satisfies Prisma.UserSelect;

Sources: apps/web/app/ee/api/admin/impersonate/route.ts:19-79, apps/web/app/ee/api/admin/impersonate/route.ts:227-245

Session Tracking and Impersonation Tokens

Tracking of active administrative impersonation sessions is managed through an in-memory tracking structure in admin-impersonation.ts. When an administrator initiates an impersonation session, the target user's email is marked as a pending impersonation event.

// Tracks emails signing in via admin impersonation links. Populated in
// CustomPrismaAdapter.useVerificationToken before the token is deleted.
const pendingAdminImpersonations = new Set<string>();
 
export const markAdminImpersonation = (email: string) => {
  pendingAdminImpersonations.add(email.toLowerCase());
};
 
export const consumeAdminImpersonation = (email: string) => {
  const isAdminImpersonation = pendingAdminImpersonations.has(
    email.toLowerCase(),
  );
 
  if (isAdminImpersonation) {
    pendingAdminImpersonations.delete(email.toLowerCase());
  }
 
  return isAdminImpersonation;
};

Sources: apps/web/lib/auth/admin-impersonation.ts:1-19

Caution

The pendingAdminImpersonations set tracks emails signing in via admin impersonation links and is populated within CustomPrismaAdapter.useVerificationToken immediately before the verification token is consumed and deleted.

Administrators can moderate platform links through administrative search and filtering endpoints and the links dashboard. The backend API handles queries with sorting and pagination.

// GET /api/admin/links
export const GET = withAdmin(async ({ searchParams }) => {
  const {
    domain,
    search,
    sort = "createdAt",
    page,
  } = searchParams as {
    domain?: string;
    search?: string;
    sort?: "createdAt" | "clicks" | "lastClicked";
    page?: string;
  };
 

Sources: apps/web/app/ee/api/admin/links/route.ts:7-20

ParameterType / OptionsDescription
domainstringFilter links by specific custom domain.
searchstringSearch query for short links or destination URLs.
sort"createdAt" | "clicks" | "lastClicked"Ordering field for query results (default: createdAt).
pagestringPagination offset index (100 items per page).

Sources: apps/web/app/ee/api/admin/links/route.ts:9-19, apps/web/app/ee/api/admin/links/route.ts:71-77

Note

When no search query is provided, the API automatically restricts queries to domains defined in DUB_DOMAINS_ARRAY created within the last 30 days, while excluding legal user accounts (LEGAL_USER_ID) or unassigned links.

Sources: apps/web/app/ee/api/admin/links/route.ts:21-40

If a search query begins with https://, the query matches the shortLink field precisely. Otherwise, it performs an OR-match searching partial substrings across both shortLink and destination url fields.

Sources: apps/web/app/ee/api/admin/links/route.ts:41-55

Workspace Disabling and Restoration

Administrative moderation includes tools to disable or restore all links associated with a workspace slug. The interface requires entering a workspace slug (prefixed with app.dub.co/) and executing actions via POST requests to workspace moderation endpoints.

const handleAction = async (action: "disable" | "restore", slug: string) => {
  const message =
    action === "disable"
      ? `Are you sure you want to disable all links for workspace "${slug}"? This will also downgrade owners to billing and members to viewer, and notify workspace owners by email.`
      : `Are you sure you want to restore all links for workspace "${slug}"? This will also revert billing users to owner and viewers to member.`;
 
  if (!window.confirm(message)) return;
 
  setPending(action);
  try {
    const res = await fetch(`/api/admin/workspaces/${action}`, {
      method: "POST",
      body: JSON.stringify({ slug }),
    });
 
    if (res.ok) {
      toast.success(
        action === "disable"
          ? "Workspace links disabled"
          : "Workspace links restored",
      );
    } else {
      const error = await res.text();
      toast.error(error || "Something went wrong. Please try again.");
    }
  } catch {
    toast.error("Network error. Please check your connection and try again.");
  } finally {
    setPending(null);
  }
};

Sources: apps/web/app/ee/admin.dub.co/dashboard/links/components/disable-restore-workspace.tsx:12-42, apps/web/app/ee/admin.dub.co/dashboard/links/page.tsx:12-20

Caution

Disabling workspace links automatically downgrades owners to billing and members to viewer roles, and dispatches email notifications to workspace owners. Restoring workspace links reverses these role changes, promoting billing users back to owners and viewers back to members.

Sources: apps/web/app/ee/admin.dub.co/dashboard/links/page.tsx:13-18, apps/web/app/ee/admin.dub.co/dashboard/links/components/disable-restore-workspace.tsx:12-17

Partner Network Oversight

Network Partner Applications and Metadata

Administrators review incoming partner applications through the network oversight dashboard at /partners/network. The application listing supports filtering by network status and country, and dynamically selects date columns based on the active status query parameter.

Status ValueDate Column IdentifierHeader Label
submittedsubmittedAtSubmitted
approvedreviewedAtApproved
rejectedreviewedAtRejected
Other/DefaultcreatedAtJoined

Sources: apps/web/app/ee/admin.dub.co/dashboard/partners/network/page.tsx:44-66

The application detail sheet provides tabs for inspecting profile metadata, associated affiliate programs, and duplicate account flags. Duplicate partner accounts are automatically flagged when applicants share matching email addresses or profile details.

return (
  <div>
    <h3 className="text-content-emphasis text-sm font-semibold">
      Duplicate partner accounts
    </h3>
    <p className="mt-1 text-sm text-neutral-500">
      These accounts likely match this applicant by email or profile details.
    </p>

Sources: apps/web/app/ee/admin.dub.co/dashboard/partners/network/network-partner-application-sheet.tsx:495-502, apps/web/app/ee/admin.dub.co/dashboard/partners/network/network-partner-application-sheet.tsx:395-442

Warning

Administrators cannot approve a partner whose current network status is already approved or trusted.

Sources: apps/web/app/ee/admin.dub.co/dashboard/partners/network/network-partner-application-sheet.tsx:382-386

Trusted Partner Management

The trusted partners interface allows administrators with the owner role to promote partners to trusted status or revoke their trusted badge. Partners can be added by their unique identifier (prefixed with pn_) or email address via /api/admin/partners/trusted.

// POST /api/admin/partners/trusted
export const POST = withAdmin(
  async ({ req }) => {
    const { partnerIdOrEmail } = z
      .object({
        partnerIdOrEmail: z.string().trim().min(1),
      })
      .parse(await req.json());
 
    if (
      !partnerIdOrEmail.startsWith("pn_") &&
      !partnerIdOrEmail.includes("@")
    ) {
      return new Response("Invalid partner ID or email.", { status: 400 });
    }
 

Sources: apps/web/app/ee/api/admin/partners/trusted/route.ts:49-64, apps/web/app/ee/admin.dub.co/dashboard/partners/trusted/page.tsx:105-129

Note

Every status transition updates the partner's change history log (changeHistoryLog) with audit metadata recording the field change from its previous state to either trusted or approved.

Sources: apps/web/app/ee/api/admin/partners/trusted/route.ts:87-97, apps/web/app/ee/api/admin/partners/trusted/route.ts:147-156

Program and Operational Tools

Affiliate Program Management and Partner Account Deletions

Administrators manage affiliate programs directly from the admin dashboard, including listing marketplace programs, updating categories and descriptions via dedicated modals, and reordering display ranks with drag-and-drop controls. Programs can be added via POST /api/admin/programs by providing a program slug, or removed permanently via DELETE /api/admin/programs/[id], which deletes associated commissions, payouts, rewards, discounts, links, customers, partner groups, and enrollments.

<AddProgramModal
  showModal={showAddProgramModal}
  setShowModal={setShowAddProgramModal}
  programSlug={newProgramSlug}
  setProgramSlug={setNewProgramSlug}
  isLoading={isAddingProgram}
  onAdd={async () => {
    if (!newProgramSlug.trim()) return;
 
    setIsAddingProgram(true);
    const res = await fetch("/api/admin/programs", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        programSlug: newProgramSlug.trim(),
      }),
    });
 
    if (!res.ok) {
      setIsAddingProgram(false);
      toast.error((await res.text()) || "Failed to add program.");
      return;
    }
 
    await mutate();
    setIsAddingProgram(false);
    setShowAddProgramModal(false);
    setNewProgramSlug("");
    toast.success("Program added to marketplace.");
  }}
/>

Sources: apps/web/app/ee/admin.dub.co/dashboard/programs/page.tsx:311-343, apps/web/app/ee/admin.dub.co/dashboard/programs/page.tsx:240-253, apps/web/app/ee/admin.dub.co/dashboard/page.tsx:34-41

Caution

Deleting a partner's Stripe Express account will fail to remove the account if the partner has already received payouts via Stripe, and will leave the partner account intact if they have already accumulated commissions or leads on Dub.

Sources: apps/web/app/ee/admin.dub.co/dashboard/page.tsx:20-32

Authentication Reset and Support Invites

Operational tools also handle account security recovery and customer engagement. Administrators can reset a user's invalidLoginAttempts counter and clear their lockedAt timestamp when accounts become locked due to failed authentication thresholds. Additionally, administrators can manually dispatch priority Slack Connect invites to users for a specific workspace via the Slack Support Invite tool, bypassing normal plan checks.

  <h2 className="text-xl font-semibold">Reset Login Attempts</h2>
  <p className="text-sm text-neutral-500">
    Reset a user's invalidLoginAttempts and lockedAt fields
  </p>
  <ResetLoginAttempts />
</div>
<div className="flex flex-col space-y-4 px-5 py-10">
  <h2 className="text-xl font-semibold">Slack Support Invite</h2>
  <p className="text-sm text-neutral-500">
    Manually send a priority Slack Connect invite to a user for a given
    workspace (bypasses the plan check).
  </p>
  <SlackSupportInvite />
</div>

Sources: apps/web/app/ee/admin.dub.co/dashboard/page.tsx:43-56

API endpoints handling administrative actions are secured by the withAdmin authorization wrapper, which validates that the requesting session belongs to an authenticated user with a registered admin role in the core project workspace (DUB_WORKSPACE_ID).

export const withAdmin =
  (
    handler: WithAdminHandler,
    { requiredRoles = [] }: { requiredRoles?: WorkspaceRole[] } = {},
  ) =>
  async (
    req: Request,
    { params: initialParams }: { params: Promise<Record<string, string>> },
  ) => {
    const params = (await initialParams) || {};
    const session = await getSession();
    if (!session?.user) {
      return new Response("Unauthorized: Login required.", { status: 401 });
    }
 
    const adminRole = await getDubAdminRole(session.user.id);
    if (!adminRole) {
      return new Response("Unauthorized: Not an admin.", { status: 401 });
    }
 
    if (requiredRoles.length > 0 && !requiredRoles.includes(adminRole)) {
      return new Response(
        `Unauthorized: Missing required admin role(s): ${requiredRoles.join(", ")}.`,
        { status: 403 },
      );
    }

Sources: apps/web/lib/auth/admin.ts:41-66, apps/web/lib/auth/admin.ts:22-39

Domain and System Analytics Monitoring

Registrar Operations and Domain Management

Workspace settings allow administrators and workspace members to manage custom domains, configure default Dub domains, and handle registrar provisioning actions. Workspaces can add custom domains, toggle auto-renewal for Dub-provisioned domains, transfer domains, and archive or delete non-provisioned domains.

{isDubProvisioned && (
  <Button
    text={
      !autoRenew ? "Enable Auto-Renew" : "Disable Auto-Renew"
    }
    variant="outline"
    onClick={() => {
      setOpenPopover(false);
      openDomainRenewalModal(!autoRenew);
    }}
    icon={
      <Repeat
        className={cn(
          "h-4 w-4",
          !autoRenew ? "text-green-600" : "text-red-600",
        )}
      />
    }
    className="h-9 justify-start px-2 font-medium"
  />
)}
 
{!primary && (
  <Button
    text="Set as Primary"
    variant="outline"
    onClick={() => {
      setOpenPopover(false);
      setShowPrimaryDomainModal(true);
    }}
    icon={<Flag2 className="h-4 w-4" />}
    className="h-9 justify-start px-2 font-medium"
  />
)}
{canSetAsProgramDomain && (
  <Button
    text="Set Program Domain"
    variant="outline"
    onClick={() => {
      setOpenPopover(false);
      setShowChangeDomainModal(true);
    }}
    icon={<ConnectedDots4 className="h-4 w-4" />}
    className="h-9 justify-start px-2 font-medium"
  />
)}
{!isDubProvisioned && (
  <Button
    text="Transfer"
    variant="outline"
    onClick={() => {
      setOpenPopover(false);
      setShowTransferDomainModal(true);
    }}
    icon={<FolderInput className="h-4 w-4" />}
    className="h-9 justify-start px-2 font-medium"
    disabledTooltip={
      primary && activeDomainsCount > 1
        ? "You cannot transfer your workspace's primary domain. Set another domain as primary to transfer this domain."
        : undefined
    }
  />
)}
<Button
  text={archived ? "Unarchive" : "Archive"}
  variant="outline"
  onClick={() => {
    setOpenPopover(false);
    setShowArchiveDomainModal(true);
  }}
  icon={<Archive className="h-4 w-4" />}
  className="h-9 justify-start px-2 font-medium"
  disabledTooltip={permissionsError || undefined}
/>
{!isDubProvisioned && (
  <Button
    text="Delete"
    variant="danger-outline"
    onClick={() => {
      setOpenPopover(false);

Sources: apps/web/ui/domains/domain-card.tsx:557-643, apps/web/app/app.dub.co/dashboard/slug/ee/settings/domains/page-client.tsx:171-221

Note

When Domain Connect callbacks return to the custom domains settings page, the client inspects search parameters for errors or success states, automatically triggering immediate domain verification revalidations followed by delayed revalidation checks at 4 and 10 seconds.

Sources: apps/web/app/app.dub.co/dashboard/slug/ee/settings/domains/page-client.tsx:78-111

Workspaces can also enable or disable default Dub branded domains for specific links by making PATCH requests to /api/domains/default.

fetch(`/api/domains/default?workspaceId=${id}`, {
  method: "PATCH",
  body: JSON.stringify({
    defaultDomains: newDefaultDomains.filter(
      (d) => d !== null,
    ),
  }),
})
  .then(async (res) => {

Sources: apps/web/app/app.dub.co/dashboard/slug/ee/settings/domains/default/page-client.tsx:102-110

Domain SlugMapped Icon ComponentDescription / Association
chatg.ptChatGPTOpenAI ChatGPT branded short links
git.newGitHubEnhancedGitHub repository short links
spti.fiSpotifySpotify track and album links
cal.linkCalendarDaysCalendar scheduling links
amzn.idAmazonAmazon product and affiliate links
ggl.linkGoogleEnhancedGoogle service links
fig.pageFigmaFigma design file links

Sources: apps/web/app/app.dub.co/dashboard/slug/ee/settings/domains/default/page-client.tsx:23-42, apps/web/app/app.dub.co/dashboard/slug/ee/settings/domains/default/page-client.tsx:78-88

Platform Analytics and Event Interfaces

The administrative portal provides system-wide analytics and event monitoring interfaces. Administrators access traffic analytics and event logs through dedicated dashboard pages wrapped in suspense boundaries with layout loaders.

export default function AdminAnalytics() {
  return (
    <Suspense fallback={<LayoutLoader />}>
      <div className="w-full">
        <Analytics adminPage />
      </div>
    </Suspense>
  );

Sources: apps/web/app/ee/admin.dub.co/dashboard/analytics/page.tsx:5-12, apps/web/app/ee/admin.dub.co/dashboard/events/page.tsx:7-16

Tip

The admin events view wraps the core EventsProvider and AnalyticsClient components with the adminPage flag enabled, allowing administrative inspection of platform-wide event streams.

Sources: apps/web/app/ee/admin.dub.co/dashboard/events/page.tsx:7-16

Was this page helpful?