Download the PHP package jeffersongoncalves/laravel-short-url without Composer
On this page you can find all versions of the php package jeffersongoncalves/laravel-short-url. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download jeffersongoncalves/laravel-short-url
More information about jeffersongoncalves/laravel-short-url
Files in jeffersongoncalves/laravel-short-url
Package laravel-short-url
Short Description A Laravel package for creating and redirecting short URLs, with caching and an extensible redirect pipeline.
License MIT
Homepage https://github.com/jeffersongoncalves/laravel-short-url
Informations about the package laravel-short-url
Laravel Short URL
Headless URL-shortening engine for Laravel. Zero dependency on Filament — works standalone in any Laravel app via its Facade or console commands.
Why this package
- High throughput. The redirect pipeline is a chain of independent, testable stages (
Illuminate\Pipeline), with the resolved link cached and analytics writes made asynchronous — no external integration failure (GeoIP, Safe Browsing, VPN detection) can ever break a redirect. - Contract-driven. Every swappable piece — analytics driver, conversion API dispatcher, DNS verifier, Safe Browsing checker, VPN detector — is an interface under
src/Contracts/, with a default implementation and extensible registries (AnalyticsDriverRegistry,PixelProviderRegistry,FilterTypeRegistry,ImporterDriverRegistry). - Minimal dependencies. Only
spatie/laravel-package-toolsandilluminate/contractsare required. GeoIP (MaxMind), multi-tenancy (stancl/tenancy), Redis (predis/predis) and QR codes (endroid/qr-code) are all optional — the package works perfectly without them, each integration guarded byclass_exists/a feature flag. - Multi-language. pt_BR, en and es ship out of the box — no hardcoded strings outside
resources/lang.
Requirements
- PHP 8.3+
- Laravel 12 or 13
Installation
Publish config, migrations and translations:
Quick usage
Redirecting itself needs no extra code: any request to GET /{urlKey} already flows through the full pipeline.
Campaign tagging (UTM)
Every link can carry its own utm_source/utm_medium/utm_campaign/utm_term/utm_content — set directly, or from a reusable, tenant-scoped UtmTemplate ("campaign"):
These values are attached to the destination URL on redirect (see strip_utm_from_destination to drop the click's own incoming utm_* first) and become the default attribution recorded on the visit whenever the click itself carries no utm_* of its own — so a link generated specifically for SMS is still correctly attributed even if whoever forwards it doesn't append query params by hand.
Set short-url.utm.required (e.g. ['utm_medium']) to make ShortUrlManager reject creating — or updating — a link that doesn't declare those fields, directly or via a template. Enforced everywhere a link is created (facade, builder, CSV/Bitly import).
QR codes
Requires the optional endroid/qr-code package (^6.0):
Encodes the link's fullUrl(). Without the package installed, each call throws QrCodeGeneratorMissing — never breaks link creation or redirects, only the QR call site itself.
Destination types
destination_type is one of single, split, or rules:
A condition's type can be device, platform, browser, country, language, referer, utm_source/utm_medium/utm_campaign, a date/time window, visit_count, vpn, or bot. Conditions default to AND; wrap a group in ['or' => [...]] for OR logic. A rule's destination can itself be a nested split array to combine targeting with rotation, and rotation picks are evaluated with statistical-significance tracking (Z-test) so you can tell when a split has a real winner.
The redirect pipeline
RenderInterstitial only fires when the link has attached retargeting pixels.
Each stage can short-circuit by returning a Response directly (wrong password, destination warning, expired link, blocked VPN, plan limit). The resolved link is cached ({host}:{key}) and invalidated automatically on saved/deleted.
Feature overview
| Area | Description |
|---|---|
| Redirecting | Configurable Base62 keys, blacklist, uniqueness per domain, 301\|302\|307\|308, single_use, max_visits, expiration with a fallback redirect. |
| Analytics | Asynchronous visit tracking (TrackShortUrlVisitJob), fast-path UA parsing, GeoIP (CDN headers / MaxMind / ip-api), bot detection, IP anonymization (IPv4 /24, IPv6 /48), daily aggregation with configurable retention. StatsAggregator breaks visits down by UTM source/medium/campaign, device, browser, OS, country, referer, and more. |
| Targeting | Nested and\|or rules by device, platform, browser, country, language, referer, UTM, date/time window, visit count, VPN, bot. Weighted A/B rotation with statistical significance (Z-test). |
| Custom domains | DNS verification (TXT/CNAME/A), per-domain routing, wildcard support, root redirect. |
| Security | Bcrypt password protection, signed-token warning page, Google Safe Browsing (sync or async blocking), VPN/proxy detection (flag or 403 block), rate limiting, full audit trail (before/after). |
| Compliance | Configurable retention (package-wide or per tenant plan), per-subject data export/deletion (LGPD/GDPR), analytics-only mode (no PII stored). |
| External analytics | GA4, Plausible, PostHog, Matomo, Umami, Mixpanel, and Segment built in; AnalyticsDriverRegistry::extend() to add any other provider. |
| Conversion tracking | Server-to-server forwarding to Meta CAPI, Google Enhanced Conversions, TikTok Events API, and LinkedIn CAPI when a conversion is recorded via ConversionApiDispatcher. |
| Alerts | Z-score anomaly detection against a 7-day baseline, notifications via mail, database, broadcast, Telegram. |
| Pixels | Retargeting pixels (Meta, Google Ads, TikTok, GA4) rendered on the interstitial, with an optional consent banner. |
| Organization | Hierarchical folders, tags, reusable UTM templates ("campaigns"), archiving. |
| Import/Export | Built-in CSV importer, Bitly API v4 as the reference per-provider importer, CSV export via CsvLinkExporter. |
| QR codes | $shortUrl->qrCode()->svg()/->png()/->dataUri() via the optional endroid/qr-code (^6.0) package. Size/margin configurable via method args. |
| ClickHouse | Alternative VisitRepository driver over ClickHouse's native HTTP interface — same contract, no client library dependency. |
| Multi-tenancy | Fully feature-flagged. Auto-scoped via stancl/tenancy when installed, or a Contracts\TenantResolver binding for any other tenancy system. Configurable plan limits (links_per_month, domains, retention_days) via Contracts\PlanResolver. Custom domain resolution pluggable via Contracts\CustomDomainResolver for apps with existing domain infra. |
Contracts\StatsAggregator::forShortUrls(array $shortUrlIds) builds a breakdown across a set of links — a dashboard overview, a scheduled report. It only does the aggregation math; which links belong in the set is always resolved by the caller through ShortUrl's own tenant-scoped query.
Configuration
Every option is documented inline in config/short-url.php. Main groups:
table_prefix, route, key, redirect, cache, tracking (includes clickhouse), domains, branding, security (password, warning, rate limit, VPN, safe browsing), compliance, audit, analytics, conversions, alerts, notifications, pixels, importers, tenancy.
Settings can also be read/written at runtime via Contracts\SettingsRepository, with a declarative schema (schema()) for building dynamic forms in the UI plugin.
Multi-tenancy without stancl/tenancy
Every tenant-scoped model (ShortUrl, CustomDomain, Folder, Tag, UtmTemplate, and settings) resolves "the current tenant" through a single class, Tenancy\TenantContext. If you have your own tenancy — a custom global scope on your own tenant model, for example — bind Contracts\TenantResolver instead of installing stancl/tenancy:
TenantResolver is checked before stancl/tenancy's tenant() helper and before the static current_tenant_id fallback. Once it returns your tenant id, scoping works exactly as it does with stancl.
Plan limits (links_per_month, domains, retention_days via tenancy.plans) work the same way — bind Contracts\PlanResolver to say which plan key a given tenant id is on; with nothing bound, every tenant is on plans.default.
Both are container bindings rather than config Closures because php artisan config:cache can't serialize a Closure — it would throw LogicException: Your configuration files are not serializable. on every deploy that runs it.
Custom domain resolution without short_url_custom_domains
If your app already maps hosts to tenants on its own (a multi-tenant SaaS with per-account custom domains, for example), bind Contracts\CustomDomainResolver instead of registering every domain in short_url_custom_domains:
The returned CustomDomain doesn't need to be persisted — build a transient instance from your own domain data. When bound, Pipeline\Stages\ResolveHost calls it instead of its own short_url_custom_domains lookup, whenever domains.enabled is true.
Artisan commands
All self-register with the scheduler (packageBooted()), respecting their config toggles:
| Command | Frequency |
|---|---|
short-url:sync-counters |
every minute (when counter buffering is on) |
short-url:aggregate-and-prune |
daily at 02:00 |
short-url:verify-domains |
every 6h |
short-url:check-safe-browsing |
daily |
short-url:detect-anomalies |
hourly |
short-url:send-scheduled-reports |
daily |
short-url:import {driver} {source} |
manual |
aggregate-and-prune prunes each tenant's visit rows against its own plan retention_days when multi-tenancy is enabled, falling back to the package-wide short-url.tracking.retention_days otherwise.
Public surface (contract with the UI plugin)
Testing
CI runs against PHP 8.4 / Laravel 13 on SQLite, MySQL, and PostgreSQL.
AI-assisted development
This package ships a Laravel Boost skill (resources/boost/skills/short-url-development/) and guideline (resources/boost/guidelines/core.blade.php) — if your project uses Boost, an AI assistant picks these up automatically and already knows the facade, contracts, destination types, campaign tagging, and conventions above.
Security Vulnerabilities
Found a security vulnerability? See SECURITY.md.
Credits
- Jefferson Gonçalves
- All contributors
License
MIT. See LICENSE.md for more information.
All versions of laravel-short-url with dependencies
illuminate/contracts Version ^12.0|^13.0
spatie/laravel-package-tools Version ^1.16