spatie/laravel-link-checker
Unmaintained: Artisan command to crawl your Laravel app and check internal/external links. Logs URLs that don’t return 2xx/3xx responses and can email broken-link reports. Configurable base URL, link-check profiles, reporters, and concurrency settings.
Installation:
composer require spatie/laravel-link-checker
Publish the config file:
php artisan vendor:publish --provider="Spatie\LinkChecker\LinkCheckerServiceProvider"
First Run: Execute the command to check all links in your app:
php artisan link-checker:check
routes/web.php and routes/api.php for HTTP links.storage/logs/laravel-link-checker.log.Quick Use Case:
* * * * * php artisan link-checker:check --quiet) to run nightly.config/link-checker.php – Customize ignored URLs, status codes, and email notifications.php artisan link-checker:check – Core command with flags like --ignore-ssl, --quiet, and --email.Spatie\LinkChecker\LinkCheckerServiceProvider – Registers the command and config.Integrate with CI/CD:
phpunit.xml or GitHub Actions workflow to fail builds on broken links:
<php>
<env name="LINK_CHECKER_FAIL_ON_BROKEN" value="true"/>
</php>
- name: Check Links
run: php artisan link-checker:check --fail-on-broken
Custom Link Sources:
LinkChecker class to scan additional files (e.g., Markdown, Blade templates):
use Spatie\LinkChecker\LinkChecker;
$checker = new LinkChecker();
$checker->addFileToCheck('/path/to/custom/file.md');
$checker->check();
Email Notifications:
link_checker.email in config/link-checker.php to send reports to stakeholders:
'email' => [
'to' => 'team@example.com',
'from' => 'monitor@example.com',
'subject' => 'Broken Links Report',
],
php artisan link-checker:check --email
Scheduled Checks:
app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
$schedule->command('link-checker:check --quiet')
->dailyAt('3:00');
}
Exclude URLs:
Use the ignore_urls config array to skip internal routes or external services:
'ignore_urls' => [
'https://example.com/api/*',
'mailto:*',
'tel:*',
],
Custom Status Codes: Override default 200-300 range in config:
'allowed_status_codes' => [200, 301, 302, 404],
Parallel Checks: For large apps, leverage Laravel’s queue system to process links in batches:
$checker->checkInParallel(5); // Process 5 links concurrently
Blade Template Links:
Ensure Blade directives like @url() or @route() resolve to absolute URLs before checking.
SSL Warnings:
--ignore-ssl, but be cautious in production (may hide real issues).--ignore-ssl temporarily:
php artisan link-checker:check --ignore-ssl
Dynamic Routes:
window.location.href) won’t be caught. Use static analysis or frontend tools (e.g., Puppeteer) for these.Rate Limiting:
'delay_between_checks' => 1000, // Milliseconds
False Positives:
allowed_status_codes.--verbose to debug:
php artisan link-checker:check --verbose
Log Inspection:
Check storage/logs/laravel-link-checker.log for detailed errors (e.g., timeouts, SSL issues).
Dry Run:
Use --dry-run to preview links without making requests:
php artisan link-checker:check --dry-run
Timeouts: Increase timeout for slow external services:
'timeout' => 30, // Seconds
Custom Checkers:
Extend Spatie\LinkChecker\Checkers\Checker to validate links against custom rules (e.g., API response schemas):
namespace App\LinkCheckers;
use Spatie\LinkChecker\Checkers\Checker;
class ApiResponseChecker extends Checker
{
public function check($url)
{
$response = $this->httpClient->get($url);
return $response->json('status') === 'success';
}
}
Database Storage: Save results to a table for historical tracking:
use Spatie\LinkChecker\Models\Link;
$links = Link::all()->where('is_broken', true);
Slack/Teams Notifications:
Hook into the link-checker.after-check event to send alerts:
// In EventServiceProvider
protected $listen = [
'Spatie\LinkChecker\Events\AfterCheck' => [
\App\Listeners\SendSlackAlert::class,
],
];
Environment-Specific Settings:
Override config in .env:
LINK_CHECKER_IGNORE_URLS=*.staging.example.com/*
LINK_CHECKER_TIMEOUT=15
Case Sensitivity:
ignore_urls patterns are case-sensitive. Use regex or lowercase URLs for consistency:
'ignore_urls' => [
'/api/.*/old-endpoint',
],
Local Development:
Exclude localhost or 127.0.0.1 in development:
'ignore_urls' => [
'http://localhost:*',
'http://127.0.0.1:*',
],
How can I help you explore Laravel packages today?