CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-linkinator

Find broken links, missing images, etc in your HTML. Scurry around your site and find all those broken links.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

configuration.mddocs/

Configuration

Configuration system supporting both programmatic options and file-based configuration with CLI flag precedence. Enables flexible setup for various scanning scenarios from simple one-off checks to complex CI/CD integrations.

Capabilities

Configuration Loading

Load and merge configuration from files with CLI flag override capabilities.

/**
 * Load configuration from files and merge with CLI flags
 * @param flags - CLI flags and options to merge with file-based config
 * @returns Promise resolving to merged configuration
 */
function getConfig(flags: Flags): Promise<Flags>;

Usage Examples:

import { getConfig } from "linkinator";

// Load config with CLI flags taking precedence
const config = await getConfig({
  concurrency: 50,
  retry: true,
  config: "./custom-linkinator.config.js"
});

// Use in scanning
const result = await check({
  path: "https://example.com",
  ...config
});

Check Options

Comprehensive configuration interface for controlling all aspects of link checking behavior.

interface CheckOptions {
  /** Number of simultaneous connections (default: 100) */
  concurrency?: number;
  /** Port for local server when scanning files */
  port?: number;
  /** URLs or file paths to check */
  path: string | string[];
  /** Recursively follow links on same root domain */
  recurse?: boolean;
  /** Request timeout in milliseconds */
  timeout?: number;
  /** Automatically parse and scan markdown files */
  markdown?: boolean;
  /** Links to skip - regex patterns or function */
  linksToSkip?: string[] | ((link: string) => Promise<boolean>);
  /** Root directory for local static server */
  serverRoot?: string;
  /** Enable directory index when linking to directories */
  directoryListing?: boolean;
  /** Automatically retry HTTP 429 responses with retry-after header */
  retry?: boolean;
  /** Automatically retry 5xx and network errors */
  retryErrors?: boolean;
  /** Maximum retry attempts for errors (default: 5) */
  retryErrorsCount?: number;
  /** Random jitter applied to error retry in milliseconds (default: 3000) */
  retryErrorsJitter?: number;
  /** URL rewrite patterns for transforming URLs before checking */
  urlRewriteExpressions?: UrlRewriteExpression[];
  /** Custom user agent string for HTTP requests (defaults to DEFAULT_USER_AGENT) */
  userAgent?: string;
}

Usage Examples:

import { check } from "linkinator";

// Basic local file scanning
const basicConfig = {
  path: "./docs/",
  markdown: true,
  recurse: true,
};

// Advanced configuration with retries and filtering
const advancedConfig = {
  path: ["https://example.com", "https://api.example.com"],
  concurrency: 25,
  timeout: 15000,
  retry: true,
  retryErrors: true,
  retryErrorsCount: 3,
  retryErrorsJitter: 5000,
  linksToSkip: [
    "mailto:.*",
    "tel:.*",
    ".*\\.pdf$"
  ],
  userAgent: "Custom Bot 1.0"  // or use DEFAULT_USER_AGENT
};

// URL rewriting for development/staging environments
const rewriteConfig = {
  path: "https://example.com",
  urlRewriteExpressions: [
    {
      pattern: /https:\/\/production\.example\.com/g,
      replacement: "https://staging.example.com"
    }
  ]
};

const result = await check(advancedConfig);

CLI Configuration Flags

Configuration flags available for command-line usage and config files.

interface Flags {
  /** Number of simultaneous connections */
  concurrency?: number;
  /** Path to configuration file */
  config?: string;
  /** Enable recursive crawling */
  recurse?: boolean;
  /** Links to skip (regex patterns) */
  skip?: string | string[];
  /** Output format (JSON, CSV, TEXT) */
  format?: string;
  /** Silent mode - suppress output */
  silent?: boolean;
  /** Log verbosity level (debug, info, warning, error, none) */
  verbosity?: string;
  /** Request timeout in milliseconds */
  timeout?: number;
  /** Enable markdown parsing */
  markdown?: boolean;
  /** Static server root directory */
  serverRoot?: string;
  /** Enable directory listings */
  directoryListing?: boolean;
  /** Enable retry on HTTP 429 */
  retry?: boolean;
  /** Enable retry on errors */
  retryErrors?: boolean;
  /** Maximum retry count */
  retryErrorsCount?: number;
  /** Retry jitter in milliseconds */
  retryErrorsJitter?: number;
  /** URL rewrite search pattern */
  urlRewriteSearch?: string;
  /** URL rewrite replacement string */
  urlRewriteReplace?: string;
}

URL Rewriting

Transform URLs before checking them, useful for testing staging environments or handling redirects.

interface UrlRewriteExpression {
  /** Regular expression pattern to match in URLs */
  pattern: RegExp;
  /** Replacement string for matched patterns */
  replacement: string;
}

Usage Examples:

import { check } from "linkinator";

// Rewrite production URLs to staging for testing
const result = await check({
  path: "https://example.com/docs/",
  recurse: true,
  urlRewriteExpressions: [
    {
      pattern: /https:\/\/cdn\.example\.com/g,
      replacement: "https://staging-cdn.example.com"
    },
    {
      pattern: /https:\/\/api\.example\.com/g,
      replacement: "https://staging-api.example.com"
    }
  ]
});

Link Filtering

Control which links are checked using regex patterns or custom functions.

Usage Examples:

import { check } from "linkinator";

// Skip common non-checkable links using regex patterns
const regexSkipResult = await check({
  path: "https://example.com",
  linksToSkip: [
    "mailto:.*",           // Skip email links
    "tel:.*",              // Skip phone links
    ".*\\.pdf$",           // Skip PDF files
    ".*linkedin\\.com.*",  // Skip LinkedIn
    "#.*"                  // Skip fragment-only links
  ]
});

// Custom function-based filtering
const customSkipResult = await check({
  path: "https://example.com",
  linksToSkip: async (url) => {
    // Skip URLs containing sensitive paths
    if (url.includes('/admin') || url.includes('/private')) {
      return true;
    }
    // Skip external URLs in test environment
    if (process.env.NODE_ENV === 'test' && !url.includes('example.com')) {
      return true;
    }
    return false;
  }
});

Configuration Files

Linkinator supports multiple configuration file formats that can be automatically discovered or explicitly specified:

JSON Configuration (linkinator.config.json):

{
  "concurrency": 50,
  "recurse": true,
  "retry": true,
  "retryErrors": true,
  "retryErrorsCount": 3,
  "timeout": 10000,
  "skip": ["mailto:.*", "tel:.*"],
  "verbosity": "warning"
}

JavaScript Configuration (linkinator.config.js):

module.exports = {
  concurrency: 50,
  recurse: true,
  retry: true,
  linksToSkip: async (url) => {
    return url.includes('private') || url.includes('admin');
  },
  timeout: 10000
};

ES Module Configuration (linkinator.config.mjs):

export default {
  concurrency: 50,
  recurse: true,
  retry: true,
  timeout: 10000,
  urlRewriteSearch: "https://production.example.com",
  urlRewriteReplace: "https://staging.example.com"
};

Internal Types

Logging and Output

enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARNING = 2,
  ERROR = 3,
  NONE = 4,
}

enum Format {
  TEXT = 0,
  JSON = 1,
  CSV = 2,
}

class Logger {
  constructor(level: LogLevel, format: Format);
  debug(message?: string): void;
  info(message?: string): void;
  warn(message?: string): void;
  error(message?: string): void;
}

Queue and Processing

interface QueueOptions {
  /** Number of simultaneous operations to allow */
  concurrency: number;
}

interface QueueItemOptions {
  /** Delay in milliseconds before executing the queued item */
  delay?: number;
}

type AsyncFunction = () => Promise<void>;

class Queue extends EventEmitter {
  constructor(options: QueueOptions);
  add(fn: AsyncFunction, options?: QueueItemOptions): void;
  onIdle(): Promise<void>;
  on(event: 'done', listener: () => void): this;
}

Static Web Server

interface WebServerOptions {
  /** Local path to mount as static web server root */
  root: string;
  /** Port for the local web server */
  port?: number;
  /** Whether to automatically compile and serve markdown */
  markdown?: boolean;
  /** Whether directories should automatically serve index pages */
  directoryListing?: boolean;
}

docs

configuration.md

index.md

link-scanning.md

tile.json