SplashUTM is a complete multi-tenant SaaS platform for URL shortening, UTM campaign management, click tracking, and analytics. Built with vanilla PHP 7.0+ and MySQL, featuring a custom lightweight MVC architecture.
- URL Shortening: Generate short, trackable links with custom or auto-generated shortcodes
- UTM Builder: Visual builder for creating campaign URLs with UTM parameters
- Campaign Management: Organize links by campaigns with default UTM settings
- Click Tracking: Comprehensive visitor tracking including:
- Device type (desktop, mobile, tablet)
- Operating system and browser
- Geographic location (country, city)
- Referrer information
- UTM parameter capture
- Unique vs. repeat visitor detection
- Real-time Dashboard: Overview of clicks, links, campaigns, and traffic sources
- Campaign Analytics: Detailed performance metrics per campaign
- Link Analytics: Individual link statistics and click history
- Traffic Source Analysis: Breakdown by source, medium, campaign, device, and location
- CSV Export: Export click data for external analysis
- Tenant Isolation: Complete data separation between tenants
- Subscription Plans: Flexible plans with configurable limits
- Usage Tracking: Monitor links created, clicks, and API calls
- Quota Enforcement: Automatic enforcement of plan limits
- Role-Based Access Control:
platform_admin: Manage tenants and system settingstenant_admin: Manage users, campaigns, and linksmarketer: Create and edit campaigns and linksread_only: View-only access to analytics
- Secure Authentication: Password hashing, session regeneration, CSRF protection
- Activity Logging: Audit trail of user actions
- Authentication: API key-based authentication
- Endpoints:
POST /api/links/create- Create short linkGET /api/links- List links (paginated)GET /api/links/{shortcode}/stats- Get link statisticsPOST /api/campaigns/create- Create campaign
- Rate Limiting: Per-tenant API call tracking
- PHP: 7.0+ compatible (no framework dependencies)
- Database: MySQL 5.7+ / MariaDB 10.2+
- Architecture: Custom MVC pattern
- Frontend: HTML, CSS, Vanilla JavaScript
- Security: PDO prepared statements, CSRF tokens, password hashing
SplashUTM/
├── app/
│ ├── controllers/ # Application controllers
│ ├── models/ # Database models
│ ├── views/ # HTML templates
│ ├── core/ # Core MVC framework
│ │ ├── Router.php
│ │ ├── Controller.php
│ │ ├── Model.php
│ │ ├── View.php
│ │ ├── Database.php
│ │ ├── Auth.php
│ │ ├── Session.php
│ │ ├── Request.php
│ │ ├── Response.php
│ │ └── CSRF.php
│ └── helpers/ # Helper classes
│ ├── ValidationHelper.php
│ ├── PaginatorHelper.php
│ ├── UTMHelper.php
│ ├── ShortCodeHelper.php
│ ├── AnalyticsHelper.php
│ ├── DeviceDetectorHelper.php
│ └── GeoIPHelper.php
├── config/ # Configuration files
├── public/ # Web root
│ ├── index.php # Application entry point
│ ├── .htaccess # Apache rewrite rules
│ └── assets/ # CSS, JS, images
├── storage/logs/ # Application logs
├── tests/ # Test scripts
├── database.sql # Database schema & seed data
├── .env.example # Environment configuration template
└── README.md # This file
- PHP 7.0 or higher
- MySQL 5.7+ or MariaDB 10.2+
- Apache with mod_rewrite (or Nginx)
- PHP Extensions:
pdo_mysql,mbstring,openssl,json
-
Clone the repository
git clone <repository-url> splashutm cd splashutm
-
Configure environment
cp .env.example .env
Edit
.envand configure your database settings:DB_HOST=localhost DB_PORT=3306 DB_NAME=splashutm DB_USER=root DB_PASS=your_password APP_URL=http://localhost -
Create database
mysql -u root -p
CREATE DATABASE splashutm CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; EXIT;
-
Import database schema
mysql -u root -p splashutm < database.sql -
Set permissions
chmod -R 755 storage/logs
-
Configure web server
Apache (recommended):
- Point DocumentRoot to
/path/to/splashutm/public - Ensure mod_rewrite is enabled
- The
.htaccessfile is already configured
Example Apache VirtualHost:
<VirtualHost *:80> ServerName splashutm.local DocumentRoot /path/to/splashutm/public <Directory /path/to/splashutm/public> AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/splashutm-error.log CustomLog ${APACHE_LOG_DIR}/splashutm-access.log combined </VirtualHost>
Nginx:
server { listen 80; server_name splashutm.local; root /path/to/splashutm/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
- Point DocumentRoot to
-
Access the application
- Open your browser and navigate to
http://localhost(or your configured domain) - Login with demo credentials (see below)
- Open your browser and navigate to
- Email:
admin@splashutm.test - Password:
admin123 - Access: Full system access, manage all tenants
-
Tenant Admin
- Email:
demo-admin@example.com - Password:
password123
- Email:
-
Marketer
- Email:
demo-marketer@example.com - Password:
password123
- Email:
-
Read-Only User
- Email:
demo-viewer@example.com - Password:
password123
- Email:
Note: Change these passwords immediately in production!
- Navigate to Campaigns → Create Campaign
- Fill in campaign details:
- Name (e.g., "Summer Sale 2024")
- Description (optional)
- Default UTM parameters:
- Source (e.g., "google", "facebook")
- Medium (e.g., "cpc", "email")
- Campaign (e.g., "summer_sale")
- Click Create Campaign
- Navigate to UTM Builder
- (Optional) Select a campaign to load default UTM values
- Enter your destination URL
- Fill in UTM parameters:
- Source: Where traffic comes from (e.g., google, facebook)
- Medium: Marketing medium (e.g., cpc, email, social)
- Campaign: Specific campaign name (e.g., summer_sale)
- Term (optional): Paid keywords
- Content (optional): Ad variation identifier
- Click Generate URL
- Copy the generated URL or create a short link directly
- Navigate to Short Links → Create Short Link
- Fill in link details:
- Title: Descriptive name for the link
- Destination URL: Full URL (with or without UTM parameters)
- Campaign (optional): Associate with a campaign
- Custom Shortcode (optional): Choose your own shortcode (4-12 alphanumeric chars)
- Expires At (optional): Set expiration date
- Max Clicks (optional): Limit number of clicks
- Click Create Short Link
- Share your short URL:
http://yourdomain.com/r/{shortcode}
- View overall statistics for the last 30 days
- See top campaigns and links
- Device and country breakdown
- Recent click activity
- Navigate to Campaigns
- Click Stats next to any campaign
- View:
- Total and unique clicks
- Click timeline
- Top links in campaign
- Source/medium breakdown
- Navigate to Short Links
- Click Stats next to any link
- View:
- Click statistics
- Geographic distribution
- Device and browser breakdown
- Recent click history
- Navigate to Analytics → Sources
- View breakdown by:
- UTM Source
- UTM Medium
- UTM Campaign
- Navigate to Analytics → Export
- Filter by campaign, link, or date range
- Download CSV file with detailed click data
All API requests require an API key in the X-API-KEY header.
Demo API Key: sk_demo_1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
curl -X POST http://localhost/api/links/create \
-H "Content-Type: application/json" \
-H "X-API-KEY: your-api-key" \
-d '{
"destination_url": "https://example.com/landing",
"title": "My Landing Page",
"utm_source": "facebook",
"utm_medium": "cpc",
"utm_campaign": "summer_sale"
}'Response:
{
"status": "success",
"short_url": "http://localhost/r/abc123",
"shortcode": "abc123",
"link_id": 5
}curl -X GET "http://localhost/api/links?page=1&per_page=20" \
-H "X-API-KEY: your-api-key"curl -X GET http://localhost/api/links/abc123/stats \
-H "X-API-KEY: your-api-key"curl -X POST http://localhost/api/campaigns/create \
-H "Content-Type: application/json" \
-H "X-API-KEY: your-api-key" \
-d '{
"name": "Holiday Campaign",
"description": "End of year sale",
"default_utm_source": "email",
"default_utm_medium": "newsletter",
"default_utm_campaign": "holiday_2024"
}'# Test database connection
php tests/test_db_connection.php
# Test short link creation
php tests/test_shortlink_creation.php
# Test UTM builder
php tests/test_utm_builder.php
# Test analytics aggregation
php tests/test_analytics_aggregation.php
# Test tenant isolation
php tests/test_tenant_isolation.php
# Test API (requires application to be running)
php tests/test_api_create_link.php- SQL Injection Prevention: PDO prepared statements throughout
- XSS Protection:
htmlspecialchars()on all output - CSRF Protection: Token-based protection on all forms
- Password Security:
password_hash()with bcrypt - Session Security:
session_regenerate_id()on login - Tenant Isolation: Strict
tenant_idfiltering on all queries - Input Validation: Comprehensive validation helpers
- API Authentication: Key-based authentication with rate limiting
- Access Control: Role-based permissions on all actions
- Activity Logging: Audit trail of user actions
- Change default passwords immediately
- Use HTTPS in production
- Set strong
APP_KEYin.env - Regularly update dependencies
- Monitor activity logs
- Enable error logging (not display) in production
- Implement rate limiting on public endpoints
- Regular database backups
The schema includes optimized indexes on:
tenant_id(all tables)shortcode(unique)clicked_at(clicks table)- UTM parameters (clicks table)
- Composite indexes for common queries
-
Caching: Implement Redis/Memcached for:
- Session storage
- Frequent analytics queries
- API rate limiting
-
Click Table Partitioning: For high-volume tenants:
ALTER TABLE clicks PARTITION BY RANGE (YEAR(clicked_at)) ( PARTITION p2024 VALUES LESS THAN (2025), PARTITION p2025 VALUES LESS THAN (2026) );
-
Log Aggregation: Use CRON jobs to:
- Pre-calculate daily/monthly stats
- Archive old click data
- Clean up activity logs older than X days
-
CDN: Serve static assets via CDN
-
Queue System: For high-traffic:
- Queue click tracking to background jobs
- Batch analytics updates
- Designed for small to medium traffic (< 100K clicks/month per tenant)
- Single database server
- Synchronous click tracking
Horizontal Scaling:
- Add load balancer (HAProxy, Nginx)
- Deploy multiple application servers
- Use session storage (Redis) instead of files
- Implement database replication (read replicas for analytics)
Vertical Scaling:
- Increase database server resources
- Optimize slow queries (use
EXPLAIN) - Add database query cache
Service Separation:
- Separate tracking service (micro-service for
/r/{shortcode}) - Dedicated analytics processing worker
- API gateway for rate limiting
Replace GeoIPHelper::lookup() stub with MaxMind GeoIP2:
composer require geoip2/geoip2:~2.0// In GeoIPHelper.php
use GeoIp2\Database\Reader;
public static function lookup($ip) {
$reader = new Reader('/path/to/GeoLite2-City.mmdb');
$record = $reader->city($ip);
return array(
'country_code' => $record->country->isoCode,
'country_name' => $record->country->name,
'city_name' => $record->city->name
);
}Replace DeviceDetectorHelper with Mobile_Detect or DeviceDetector library.
Implement in AuthController::forgotPassword() using PHPMailer or similar.
1. 404 on all routes
- Ensure
.htaccessexists in/public - Enable Apache mod_rewrite:
sudo a2enmod rewrite - Check AllowOverride in Apache config
2. Database connection error
- Verify credentials in
.env - Check MySQL service is running
- Ensure database exists
3. CSRF token errors
- Clear browser cookies
- Ensure sessions are working (
session.save_pathwritable)
4. Short links not redirecting
- Check shortcode exists in database
- Verify link is active (
is_active = 1) - Check expiration and max clicks
5. Analytics showing no data
- Ensure clicks are being recorded
- Check date range filters
- Verify tenant isolation (correct tenant_id)
This is a demo/educational project. For production use:
- Add comprehensive error handling
- Implement proper logging framework
- Add unit tests (PHPUnit)
- Implement database migrations
- Add internationalization (i18n)
- Implement proper email system
- Add two-factor authentication
- Implement webhook notifications
This project is provided as-is for educational purposes.
For issues and questions, please check:
- This README
- Code comments in source files
- Test files for usage examples
SplashUTM - Professional URL Shortener & UTM Campaign Manager