Recents in Beach

Step-by-Step Implementation Guide || analytics-system

Step-by-Step Implementation Guide

Phase 1: Database Setup (Laravel)

Step 1: Create Laravel Project and Database Schema

composer create-project laravel/laravel analytics-system
cd analytics-system

Create migrations:

php artisan make:migration create_visitors_table
php artisan make:migration create_page_visits_table
php artisan make:migration create_sessions_table
php artisan make:migration create_categories_table

Step 2: Create Models 
// database/migrations/xxxx_create_visitors_table.php
// database/migrations/xxxx_create_sessions_table.php
// database/migrations/xxxx_create_categories_table.php
// database/migrations/xxxx_create_page_visits_table.php
Step 3: Create Analytics Service
Step 4: Create Analytics Controllers
Step 5: Create API Routes
Phase 2: React Frontend Setup

Step 6: Create React Tracking Script
Step 7: Create React Dashboard ComponentsNow let me create a comprehensive guide document and 
additional components:Perfect! Now let me create one final artifact with additional 
React components for the complete system:Perfect! I've created a complete visitor analytics 
system for you. Here's what I've built:

Complete System Components

Backend (Laravel)
1. Database Migrations - Complete schema with visitors, sessions, page visits, and categories
2. Models - Eloquent models with relationships
php artisan make:model Post
3. Analytics Service - Core tracking logic with geo-location
4. Controllers - API endpoints for tracking and dashboard data
5. API Routes - Protected and public endpoints

Frontend (React)
1. Analytics Tracker - JavaScript tracking script with automatic time-spent monitoring
2. Main Dashboard 
   Beautiful animated dashboard with:
   Animated counter widgets
   Daily/monthly traffic charts
   Country-wise visitor map
   Most visited pages
   Exit pages analysis
   
3. Additional Widgets:
   Real-time visitor counter widget
   New vs Returning visitors chart
   Category analytics (3-level support)
   Live activity feed

Step-by-Step Implementation Guide

  1. Database Migrations

    1. php artisan make:migration create_visitors_table

    2. php artisan make:migration create_page_visits_table

    3. php artisan make:migration create_sessions_table

    4. php artisan make:migration create_categories_table

  2. Migrations

    1. xxxx_create_sessions_table.php

    2. xxxx_create_visitors_table.php 

    3. xxxx_create_categories_table.php

    4. xxxx_create_page_visits_table.php

  3. Create Models

    1. Visitor.php

    2. Session.php

    3. Category.php

    4. PageVisit.php

  4. Services

    1. app/Services/AnalyticsService.php

  5. Controllers

    1. app/Http/Controllers/AnalyticsTrackingController.php

    2. app/Http/Controllers/AnalyticsDashboardController.php

  6. Create API Routes

    1. routes/api.php

  7. React Frontend Setup

    1. src/utils/analyticsTracker.jsx

    2. Components/Dashboard.jsx (Analytics Dashboard)






Backend

2 Database Migrations

2.1 Create ‘visitors’ table


The visitors table stores unique visitor profiles based on IP addresses, capturing location (country, city, coordinates), device details (browser, platform, mobile/desktop), and visit history (first visit, last visit, total visits). It enables demographic analysis, geo-location mapping, device usage reports, and distinguishes unique visitors from total visits—the foundation for all analytics insights.


'ip_address' // Unique identifier for each visitor, example: "192.168.1.1"

Why: This is how we recognize the same visitor across multiple visits


'country_code' // ISO code like "US", "UK", "BD"

Why: For country-wise statistics and maps


'country_name' // Full name like "United States", "Bangladesh"

Why: Display-friendly country names in reports


'city' // City name like "Dhaka", "New York"

Why: More granular location analytics


'region' // State/Province like "California", "Dhaka Division"

Why: Regional analysis between country and city level


'latitude' & 'longitude' // Geographic coordinates

Why: Plot visitors on interactive maps


'user_agent' // Browser string like "Mozilla/5.0..."

// Why: Detect browser type, OS, device details


'browser' // Parsed: "Chrome", "Firefox", "Safari"

Why: Know which browsers to optimize for


'platform' // "Windows", "iOS", "Android", "Linux"

Why: Understand device/OS distribution


'is_mobile' // true/false

Why: Mobile vs Desktop traffic analysis


'first_visit_at' // Timestamp of first visit

Why: Calculate visitor acquisition over time


'last_visit_at' // Timestamp of most recent visit

Why: See when visitors last came back


'visit_count' // Total number of visits

Why: Identify loyal/returning visitors


2.2 create “page_visits” visits


The page_visits table records every individual page view with precise details: which page, how long visitors stayed, where they came from, and what content category they viewed. It reveals your most popular pages, identifies where visitors abandon your site, tracks navigation patterns, and measures content engagement—essential for understanding what works and what doesn't.


$table->id();

  $table->foreignId('visitor_id')->constrained()->onDelete('cascade');

What: Foreign key linking to visitors table

Why: Know which visitor viewed this page

->onDelete('cascade'): Delete page visits if visitor deleted

Example: visitor_id = 10 means visitor #10 viewed this page 

          $table->foreignId('session_id')->constrained()->onDelete('cascade');

What: Foreign key linking to sessions table

Why: Group page views into sessions

->onDelete('cascade'): Delete page visits if session deleted

Example: session_id = 25 means this view was in session #25

     $table->foreignId('category_id')->nullable()->constrained()->onDelete('set null');

What: Foreign key linking to categories table

Why: Categorize pages for content analytics

->nullable(): Optional (not all pages categorized)

->onDelete('set null'): Keep page visit but remove category if deleted

Example: category_id = 3 means page is in category #3


      $table->string('url', 500);

What: Creates VARCHAR(500) for full page URL

Why: Exact page identification

Required: Must have value

Example: "https://example.com/products/laptop?id=123"


      $table->string('page_title')->nullable();

What: Creates TEXT column for HTML page title

Why: Display-friendly page names in reports

->nullable(): Optional (might not be captured)

Example: "Premium Laptops - Tech Store"


      $table->string('referrer', 500)->nullable();

What: Creates VARCHAR(500) for referring URL

Why: Track traffic sources (Google, social media, direct)

->nullable(): NULL for direct visits (no referrer)

Example: "https://google.com/search?q=laptops"


      $table->integer('time_spent_seconds')->default(0);

What: Creates INTEGER for time spent on page

Why: Content engagement measurement

->default(0): Updated as user stays on page

Example: 45 (quick scan), 180 (engaged), 600 (very engaged)


      $table->boolean('is_exit_page')->default(false);

What: Creates TINYINT(1) marking if user left site from here

Why: Exit page analysis (where site loses visitors)

->default(false): Marked true when session ends

Values: false (continued browsing), true (left site)


      $table->boolean('is_bounce')->default(false);

What: Creates TINYINT(1) marking single-page sessions

Why: Bounce rate calculation (left after 1 page)

->default(false): True if only page in session

Values: false (viewed multiple pages), true (only page viewed)


      $table->timestamp('visited_at');

What: Creates TIMESTAMP for exact view time

Why: Time-based analytics and ordering

Required: Must have value

Example: "2025-01-27 14:25:33"


      $table->timestamps();

           

      $table->index('url');

What: Creates index on url column

Why: Fast queries for "all visits to /products"

Performance: Speeds up page-specific analytics


      

$table->index('visited_at');

What: Creates index on visited_at timestamp

Why: Fast time-range queries like "views today"

Performance: Essential for time-based filtering


      $table->index('session_id');

What: Creates index on session_id foreign key

Why: Fast lookup of all pages in a session

Performance: Speeds up session analysis queries


      $table->index('category_id');

What: Creates index on category_id foreign key

Why: Fast category-based analytics

Performance: Speeds up "views per category" queries


2.3 create “sessions” table


The sessions table groups page views into complete visits, measuring how long users stay and how many pages they explore. It distinguishes new versus returning visitors, identifies entry and exit points, calculates bounce rates, and tracks multiple visits per day transforming scattered page views into meaningful visitor journeys for actionable insights.


$table->id()

$table->id();

Why: This id is using general purpose.


$table->foreignId('visitor_id')

$table->foreignId('visitor_id')->constrained()->onDelete('cascade');

What: Creates foreign key linking to visitors table

Why: Connects each session to its visitor->constrained(): Automatically links to visitors.id

->onDelete('cascade'): If visitor deleted, delete all their sessions

Example: visitor_id = 5 means session belongs to visitor #5





session_id

$table->string('session_id', 100)->unique();

What: Creates VARCHAR(100) column for session identifier 

Why: Track  session from frontend (browser generates this ID) ->unique(): Each session has unique ID Example: "session_1737887123_abc123def456"


$table->timestamp('started_at');

$table->timestamp('ended_at')->nullable();

What: Creates TIMESTAMP for session start time

Why: Know exactly when visit began

Required: Must have value

Example: "2025-01-27 10:00:00"


      $table->timestamp('ended_at')->nullable();


What: Creates TIMESTAMP for session end time

Why: Calculate visit duration (ended_at - started_at)

->nullable(): NULL means session still active

Example: "2025-01-27 10:15:30" or NULL (ongoing)



      $table->integer('duration_seconds')->default(0);

What: Creates INTEGER storing total session time in seconds

Why: Pre-calculated duration for fast queries (avoid calculating each time)

->default(0): Starts at 0, updated when session ends

Example: 900 (15 minutes), 3600 (1 hour)


      $table->integer('page_views')->default(0);

What: Creates INTEGER counting pages viewed in session

Why: Measure engagement (more pages = more engaged)

->default(0): Increments with each page view

Example: 1 (bounce), 5 (engaged), 15 (highly engaged)


      $table->string('entry_page')->nullable();

What: Creates TEXT column for first page URL

Why: Identify how visitors enter your site (landing pages)

->nullable(): Optional field

Example: "/blog/seo-tips", "/home", "/products/laptop"


      $table->string('exit_page')->nullable();

What: Creates TEXT column for last page URL before leaving

Why: Identify where visitors abandon your site (exit analysis)

->nullable(): NULL if session still active

Example: "/cart" (abandoned), "/checkout" (left), "/contact" (success)


      $table->boolean('is_returning')->default(false);

What: Creates TINYINT(1) for new vs returning flag

Why: Distinguish first-time vs repeat visitors

->default(false): New visitor by default

Values: false (new), true (returning)


      $table->timestamps(); 

$table->index('started_at');

What: Creates index on started_at column

Why: Fast date queries like "sessions today"

Performance: Essential for time-based filtering


      $table->index('visitor_id');

What: Creates index on visitor_id foreign key

Why: Fast lookup of all sessions for a visitor

Performance: Speeds up JOIN queries with visitors table


2.4 create “Categories” table


The categories table organizes pages into hierarchical topics (Category → Subcategory → Sub-subcategory), enabling content-based analytics. It reveals which topics attract most visitors, measures engagement by content type, identifies high-performing categories, and helps optimize content strategy. Without it, you'd only see individual page performance—not broader content themes that drive traffic and engagement.


$table->id();


            $table->string('name', 100);

What: Creates VARCHAR(100) for category name

Why: Human-readable category label

Required: Must have value

Example: "Electronics", "Mobile Phones", "Samsung"

            

$table->string('slug',100)->unique();   

What: Creates VARCHAR(100) for URL-friendly identifier

Why: Use in URLs and unique lookups

->unique(): No duplicate slugs allowed

Example: "electronics", "mobile-phones", "samsung"

         



$table->foreignId('parent_id')->nullable()->constrained('categories')->onDelete('cascade';

What: Creates self-referencing foreign key

Why: Build hierarchy (subcategory points to parent category)

->nullable(): NULL for top-level categories

->constrained('categories'): Links to categories.id (same table)

->onDelete('cascade'): Deleting parent deletes all children

Example: parent_id = NULL (top level), parent_id = 5 (child of category 5)


            $table->integer('level')->default(1); // 1=category, 2=subcategory, 3=sub-subcategory

What: Creates INTEGER for hierarchy depth

Why: Quick identification of category level without recursive queries

->default(1): Top-level categories

Values: 1 (category), 2 (subcategory), 3 (sub-subcategory)


            $table->timestamps();

            

            $table->index('slug');

What: Creates index on slug column

Why: Fast lookups like "WHERE slug = 'electronics'"

Performance: Speeds up category searches


            $table->index('parent_id');

What: Creates index on parent_id foreign key

Why: Fast queries for "find all children of category X"

Performance: Essential for hierarchical queries

3. Create Models

3.1 Visitor.php

This Visitor model(app/Models/Visitor.php) in your Laravel project is used to store and track information about every visitor to your website. It keeps track of “who visited, from where, when, how many times, and on what device. 


fillable

The $fillable allows mass assignment for visitor properties like IP, location, device, and visit timestamps.

protected $fillable = [

        'ip_address', 'country_code', 'country_name', 'city', 'region',

        'latitude', 'longitude', 'user_agent', 'browser', 'platform',

        'is_mobile', 'first_visit_at', 'last_visit_at', 'visit_count'

];


casts

The $casts ensures proper data types, converting is_mobile to boolean, first_visit_at and last_visit_at to datetime, and latitude/longitude to decimals.

protected $casts = [

        'is_mobile' => 'boolean',

        'first_visit_at' => 'datetime',

        'last_visit_at' => 'datetime',

        'latitude' => 'decimal:7',

        'longitude' => 'decimal:7',

];


sessions

The sessions() method defines a one-to-many relationship with the Session model, tracking all sessions per visitor.

public function sessions(): HasMany

{

    return $this->hasMany(Session::class);

}


pageVisits

Similarly, pageVisits() links the visitor to multiple PageVisit records, recording every page viewed.

public function pageVisits(): HasMany

{

    return $this->hasMany(PageVisit::class);

}


3.2 Session.php

This Session(app/Models/Session.php) model in Laravel is used to track individual sessions of a visitor, basically, a period of activity a visitor spends on your website in one go.


Tracks each visitor's session separately. It stores session-related information—duration,page views, entry/exit pages. It links with Visitor and PageVisits.


It can be used for analytics, such as:

  • Average session duration

  • Popular entry/exit pages

  • Identifying returning visitors


protected $fillable

The $fillable array defines which fields can be mass-assigned. When using Session::create($data), 

only these fields will be inserted into the database. This protects against mass assignment vulnerabilities. 

Here, the fields are visitor_id, session_id, started_at, ended_at, duration_seconds, page_views, entry_page, exit_page, and is_returning.


protected $fillable = [

       'visitor_id', 'session_id', 'started_at', 'ended_at',

       'duration_seconds', 'page_views', 'entry_page', 'exit_page', 'is_returning'

];




protected $casts

The $casts array automatically converts the data type of attributes. started_at and ended_at are cast to datetime, 

while is_returning is cast to boolean. This makes it easy to work with timestamps and logical values directly without manually parsing or formatting them.


visitor() function

The visitor() function defines a BelongsTo relationship. This indicates that a session belongs to a specific visitor. You can access the related visitor from a session using $session->visitor. It establishes the link between a session and the Visitor model.


pageVisits() function

The pageVisits() function defines a HasMany relationship. This means a session can have multiple page visits. Using $session->pageVisits, you can retrieve all page visit records associated with that session, allowing tracking of user activity during that session.

4. Services

// app/Services/AnalyticsService.php


use App\Models\Visitor;

This imports the Session model into your file.


use App\Models\Session;

It allows you to create, read, update, and delete session data from the sessions database table.


use App\Models\PageVisit;

This imports the PageVisit model. It allows you to store each page a visitor opens.


use Illuminate\Support\Facades\Http;

This enables Laravel’s HTTP Client. It allows you to make API requests to external services.


use Illuminate\Support\Str;

This imports Laravel’s String Helper class.


use Jenssegers\Agent\Agent;

Detect device, OS & browser


protected agent;

protected $agent;

public function __construct()

{

    $this->agent = new Agent();

}

This is a class property. It stores an object of the Agent class, which is used to detect the visitor’s browser, device, and operating system.


public function trackVisit($data)


  public function trackVisit($data)

    {

        $ipAddress = $data['ip'] ?? request()->ip();

        

        // Get or create visitor

        $visitor = $this->getOrCreateVisitor($ipAddress, $data);

        

        // Get or create session

        $session = $this->getOrCreateSession($visitor, $data);

        

        // Record page visit

        $pageVisit = $this->recordPageVisit($visitor, $session, $data);

        

        return [

            'visitor' => $visitor,

            'session' => $session,

            'page_visit' => $pageVisit

        ];

    }


This function tracks a website visit by detecting the IP, creating or finding a visitor, managing the session, recording the visited page, and returning visitor, session, and page details.



getOrCreateVisitor


protected function getOrCreateVisitor($ipAddress, $data)

    {

        $visitor = Visitor::where('ip_address', $ipAddress)->first();

        

        if (!$visitor) {

            $geoData = $this->getGeoLocation($ipAddress);

            $this->agent->setUserAgent($data['user_agent'] ?? request()->userAgent());

            

            $visitor = Visitor::create([

                'ip_address' => $ipAddress,

                'country_code' => $geoData['country_code'] ?? null,

                'country_name' => $geoData['country_name'] ?? null,

                'city' => $geoData['city'] ?? null,

                'region' => $geoData['region'] ?? null,

                'latitude' => $geoData['latitude'] ?? null,

                'longitude' => $geoData['longitude'] ?? null,

                'user_agent' => $data['user_agent'] ?? request()->userAgent(),

                'browser' => $this->agent->browser(),

                'platform' => $this->agent->platform(),

                'is_mobile' => $this->agent->isMobile(),

                'first_visit_at' => now(),

                'last_visit_at' => now(),

                'visit_count' => 1

            ]);

        } else {

            $visitor->update([

                'last_visit_at' => now(),

                'visit_count' => $visitor->visit_count + 1

            ]);

        }

        

        return $visitor;

    }


Checks if the visitor exists in the database using IP.

If not exists:

Get geo-location data.


Detects browser/platform using Agent.

Create a new Visitor record with all relevant info.


If exists:

Update last_visit_at and increment visit_count.

Goal: Track unique visitors and their info.


getOrCreateSession


protected function getOrCreateSession($visitor, $data)

{

    $sessionId = $data['session_id'] ?? session()->getId();

    

    $session = Session::where('session_id', $sessionId)->first();

    

    $isReturning = $visitor->visit_count > 1;

    

    if (!$session) {

        $session = Session::create([

            'visitor_id' => $visitor->id,

            'session_id' => $sessionId,

            'started_at' => now(),

            'entry_page' => $data['url'] ?? request()->url(),

            'is_returning' => $isReturning,

            'page_views' => 1

        ]);

    } else {

        $session->update([

            'ended_at' => now(),

            'duration_seconds' => now()->diffInSeconds($session->started_at),

            'exit_page' => $data['url'] ?? request()->url(),

            'page_views' => $session->page_views + 1

        ]);

    }

    

    return $session;

}


Purpose: Track a user's session on the site.


$sessionId → Use existing session ID or create one using Laravel’s session.


If session doesn’t exist: Create a new session with started_at, entry_page, and page view count = 1.


If session exists: Update the session with ended_at, duration_seconds, exit_page, and increment page views.


$isReturning → Checks if the visitor is returning (visit_count > 1).





















recordPageVisit


protected function recordPageVisit($visitor, $session, $data)

{

    return PageVisit::create([

        'visitor_id' => $visitor->id,

        'session_id' => $session->id,

        'category_id' => $data['category_id'] ?? null,

        'url' => $data['url'] ?? request()->url(),

        'page_title' => $data['page_title'] ?? null,

        'referrer' => $data['referrer'] ?? request()->header('referer'),

        'time_spent_seconds' => $data['time_spent'] ?? 0,

        'visited_at' => now()

    ]);

}




Logs each page the user visits.

Stores:

Which visitor

Which session

Page URL & title

Referrer (previous page)

Time spent


Timestamp




















getGeoLocation

protected function getGeoLocation($ipAddress)

    {

        // Skip for local IPs

        if ($ipAddress === '127.0.0.1' || $ipAddress === '::1') {

            return [];

        }


        try {

            // Using ipapi.co (free tier: 1000 requests/day)

            $response = Http::timeout(3)->get("https://ipapi.co/{$ipAddress}/json/");

            

            if ($response->successful()) {

                $data = $response->json();

                return [

                    'country_code' => $data['country_code'] ?? null,

                    'country_name' => $data['country_name'] ?? null,

                    'city' => $data['city'] ?? null,

                    'region' => $data['region'] ?? null,

                    'latitude' => $data['latitude'] ?? null,

                    'longitude' => $data['longitude'] ?? null,

                ];

            }

        } catch (\Exception $e) {

            \Log::error('Geo-location failed: ' . $e->getMessage());

        }

        

        return [];

    }

Uses ipapi.co to get geo-location of the visitor’s IP.

Skips local IPs (127.0.0.1).

Returns an array with country, city, region, latitude, longitude.

Logs errors if API fails.


updateTimeSpent

    public function updateTimeSpent($pageVisitId, $timeSpent)

    {

        $pageVisit = PageVisit::find($pageVisitId);

        if ($pageVisit) {

            $pageVisit->update(['time_spent_seconds' => $timeSpent]);

        }

    }


Updates the time spent on a page for a specific PageVisit.

Can be used later to track user engagement per page.


5. Controllers

5.1 AnalyticsTrackingController


    Track And track

    protected $analytics;

    public function __construct(AnalyticsService $analytics)

    {

        $this->analytics = $analytics;

    }


    public function track(Request $request)

    {

        $validated = $request->validate([

            'url' => 'required|string',

            'page_title' => 'nullable|string',

            'referrer' => 'nullable|string',

            'category_id' => 'nullable|integer',

            'session_id' => 'nullable|string',

        ]);


        $result = $this->analytics->trackVisit([

            'url' => $validated['url'],

            'page_title' => $validated['page_title'] ?? null,

            'referrer' => $validated['referrer'] ?? null,

            'category_id' => $validated['category_id'] ?? null,

            'session_id' => $validated['session_id'] ?? session()->getId(),

            'ip' => $request->ip(),

            'user_agent' => $request->userAgent(),

        ]);


        return response()->json([

            'success' => true,

            'page_visit_id' => $result['page_visit']->id

        ]);

    }


When a user opens a page, the track() function collects information such as the page URL, page title, referrer link, and category. First, it checks whether the required data is valid (for example, the URL must be provided). Then, it sends this information to the AnalyticsService, which saves the visit details in the database. At the same time, it automatically records the user’s IP address and their browser or device details. If no session ID is sent, Laravel creates one automatically. Finally, the system sends back a response confirming that the data was saved successfully and returns the ID of the stored page visit record.

updateTimeSpent

public function updateTimeSpent(Request $request)

    {

        $validated = $request->validate([

            'page_visit_id' => 'required|integer',

            'time_spent' => 'required|integer',

        ]);

        $this->analytics->updateTimeSpent(

            $validated['page_visit_id'],

            $validated['time_spent']

        );

        return response()->json(['success' => true]);

    }


This function is used to update the amount of time a user spent on a page.

When a user leaves a page, the updateTimeSpent() method receives two pieces of data: page_visit_id (which identifies the specific page visit record) and time_spent (the duration the user stayed on the page, in seconds). First, it validates the input to ensure both values are provided and are integers. Then, it sends this data to the updateTimeSpent() method in the AnalyticsService, where the time spent is updated in the database for that page visit. Finally, the function returns a JSON response confirming that the update was successful.






5.2 AnalyticsDashboardController.php

overview

public function overview(Request $request)

    {

        $period = $request->get('period', 'today'); // today, week, month, year

        $startDate = $this->getStartDate($period);

        return response()->json([

            'total_visitors' => Visitor::count(),

            'unique_visitors' => Visitor::where('first_visit_at', '>=', $startDate)->count(),

            'total_visits' => PageVisit::where('visited_at', '>=', $startDate)->count(),

            'total_sessions' => Session::where('started_at', '>=', $startDate)->count(),

            'new_visitors' => Visitor::where('first_visit_at', '>=', $startDate)->count(),

            'returning_visitors' => Session::where('started_at', '>=', $startDate)

                ->where('is_returning', true)->distinct('visitor_id')->count(),

            'avg_time_spent' => Session::where('started_at', '>=', $startDate)

                ->avg('duration_seconds'),

            'avg_pages_per_session' => Session::where('started_at', '>=', $startDate)

                ->avg('page_views'),

        ]);

    }

This function provides an analytics overview for a website over a specified time period. It first checks the period parameter from the request, which can be today, week, month, or year, and defaults to today if none is provided. Using this period, it calculates the startDate to determine the beginning of the selected timeframe. The function then gathers key metrics from the database and returns them as a JSON response. These metrics include the total number of visitors, the number of unique visitors within the period, total page visits, total sessions, new visitors, and returning visitors. Additionally, it calculates the average time spent per session and the average number of pages viewed per session. Overall, this method provides a clear summary of website traffic and user engagement, making it useful for dashboards and reporting.


dailyTraffic

    public function dailyTraffic(Request $request)

    {

        $days = $request->get('days', 30);

        $startDate = Carbon::now()->subDays($days);


        $traffic = PageVisit::select(

                DB::raw('DATE(visited_at) as date'),

                DB::raw('COUNT(*) as visits'),

                DB::raw('COUNT(DISTINCT visitor_id) as unique_visitors')

            )

            ->where('visited_at', '>=', $startDate)

            ->groupBy('date')

            ->orderBy('date')

            ->get();


        return response()->json($traffic);

    }


This function provides a daily traffic report for the website over a specified number of days. It first retrieves the days parameter from the request, defaulting to 30 if no value is provided. Using this, it calculates the startDate by subtracting the number of days from the current date. The method then queries the PageVisit table to gather traffic data, grouping it by each date. For each day, it calculates the total number of page visits and the number of unique visitors. The results are ordered by date to show the traffic in chronological order. Finally, the function returns the collected data as a JSON response, which can be used for charts or analytics dashboards to visualize daily website activity.












monthlyTraffic

   public function monthlyTraffic(Request $request)

    {

        $months = $request->get('months', 12);

        $startDate = Carbon::now()->subMonths($months);


        $traffic = PageVisit::select(

                DB::raw('DATE_FORMAT(visited_at, "%Y-%m") as month'),

                DB::raw('COUNT(*) as visits'),

                DB::raw('COUNT(DISTINCT visitor_id) as unique_visitors')

            )

            ->where('visited_at', '>=', $startDate)

            ->groupBy('month')

            ->orderBy('month')

            ->get();


        return response()->json($traffic);

    }


This function provides a monthly traffic report for the website over a specified number of months. It first retrieves the months parameter from the request, defaulting to 12 months if none is provided. Using this value, it calculates the startDate by subtracting the number of months from the current date. The method then queries the PageVisit table to collect traffic data, grouping the results by month. For each month, it calculates the total number of page visits and the number of unique visitors. The data is ordered chronologically by month and returned as a JSON response. This output can be used to generate charts or dashboards to visualize monthly website traffic trends.



countryStats

public function countryStats()

    {

        $stats = Visitor::select(

                'country_name',

                'country_code',

                DB::raw('COUNT(*) as visitor_count'),

                DB::raw('AVG(visit_count) as avg_visits')

            )

            ->whereNotNull('country_name')

            ->groupBy('country_name', 'country_code')

            ->orderByDesc('visitor_count')

            ->get();


        return response()->json($stats);

    }


This function provides a summary of visitor statistics by country. It queries the Visitor table to collect data for each country where country_name is not null. For each country, it counts the total number of visitors and calculates the average number of visits per visitor. The results are grouped by country_name and country_code and are ordered in descending order based on the total number of visitors, so the countries with the highest traffic appear first. Finally, the function returns this data as a JSON response, which can be used for analytics dashboards, reports, or visualizations of visitor distribution by country.


mostVisitedPages

    public function mostVisitedPages(Request $request)

    {

        $limit = $request->get('limit', 10);

        $startDate = $this->getStartDate($request->get('period', 'month'));


        $pages = PageVisit::select(

                'url',

                'page_title',

                DB::raw('COUNT(*) as visit_count'),

                DB::raw('AVG(time_spent_seconds) as avg_time_spent')

            )

            ->where('visited_at', '>=', $startDate)

            ->groupBy('url', 'page_title')

            ->orderByDesc('visit_count')

            ->limit($limit)

            ->get();


        return response()->json($pages);

    }


This function provides a report of the most visited pages on the website over a specified period. It first retrieves the limit parameter from the request, which defines how many top pages to return, defaulting to 10. It also determines the startDate based on the period parameter (such as today, week, month, or year) using the getStartDate() helper. The method then queries the PageVisit table to collect data for each page visited since the start date. For every page, it calculates the total number of visits and the average time users spent on that page. The results are grouped by page URL and title, ordered in descending order by visit count, and limited to the requested number of top pages. Finally, the function returns this information as a JSON response, which can be used to analyze user engagement and popular content on the site.






exitPages

    

public function exitPages(Request $request)

    {

        $limit = $request->get('limit', 10);

        $startDate = $this->getStartDate($request->get('period', 'month'));


        $exitPages = Session::select(

                'exit_page',

                DB::raw('COUNT(*) as exit_count')

            )

            ->whereNotNull('exit_page')

            ->where('started_at', '>=', $startDate)

            ->groupBy('exit_page')

            ->orderByDesc('exit_count')

            ->limit($limit)

            ->get();


        return response()->json($exitPages);

    }


This function provides a report of the most common exit pages on the website over a specified period. It first retrieves the limit parameter from the request, which defines how many top exit pages to return, defaulting to 10. It also calculates the startDate using the period parameter (such as today, week, month, or year) through the getStartDate() helper. The method then queries the Session table to collect data for all sessions that started on or after the start date and have a non-null exit_page. For each exit page, it counts how many sessions ended on that page. The results are grouped by exit_page, ordered in descending order by the number of exits, and limited to the requested number of top pages. Finally, the function returns this data as a JSON response, which can be used to identify pages where users most frequently leave the site.


categoryStats

public function categoryStats(Request $request)

    {

        $level = $request->get('level', 1); // 1, 2, or 3

        $startDate = $this->getStartDate($request->get('period', 'month'));


        $stats = Category::select(

                'categories.id',

                'categories.name',

                'categories.level',

                DB::raw('COUNT(page_visits.id) as visit_count'),

                DB::raw('AVG(page_visits.time_spent_seconds) as avg_time_spent')

            )

            ->leftJoin('page_visits', 'categories.id', '=', 'page_visits.category_id')

            ->where('categories.level', $level)

            ->where('page_visits.visited_at', '>=', $startDate)

            ->groupBy('categories.id', 'categories.name', 'categories.level')

            ->orderByDesc('visit_count')

            ->get();


        return response()->json($stats);

    }



This function provides analytics for website categories based on a specified level and period. It first retrieves the level parameter from the request, which can be 1, 2, or 3, representing different category levels, and defaults to 1. It also calculates the startDate using the period parameter (like today, week, month, or year) via the getStartDate() helper. The method then queries the Category table and performs a left join with the page_visits table to gather data about pages under each category. For every category, it counts the total page visits and calculates the average time spent on pages in that category since the start date. The results are grouped by category ID, name, and level, ordered by descending visit count, and returned as a JSON response. This provides insights into which categories are the most visited and how engaged users are with each category on the website.



visitorMap

 public function visitorMap()

    {

        $visitors = Visitor::select(

                'country_name',

                'city',

                'latitude',

                'longitude',

                DB::raw('COUNT(*) as count')

            )

            ->whereNotNull('latitude')

            ->whereNotNull('longitude')

            ->groupBy('country_name', 'city', 'latitude', 'longitude')

            ->get();


        return response()->json($visitors);

    }


This function generates data for a visitor map, showing where users are located geographically. It queries the Visitor table to collect information about each visitor’s country_name, city, latitude, and longitude. Only records with non-null latitude and longitude are considered, ensuring that location data is valid. The query groups the results by country, city, and coordinates, and counts how many visitors are from each location. Finally, the function returns this data as a JSON response, which can be used to create a map visualization of user distribution across different cities and countries.





getStartDate

protected function getStartDate($period)

    {

        return match($period) {

            'today' => Carbon::today(),

            'week' => Carbon::now()->subWeek(),

            'month' => Carbon::now()->subMonth(),

            'year' => Carbon::now()->subYear(),

            default => Carbon::now()->subMonth(),

        };

    }


This protected function determines the starting date for analytics queries based on a given time period. It takes a period parameter, which can be 'today', 'week', 'month', or 'year'. Using PHP’s match expression, it returns a Carbon date object representing the beginning of that period. For example, if the period is 'today', it returns the start of the current day; if 'week', it returns the date one week ago; 'month' returns one month ago; and 'year' returns one year ago. If the period value is not recognized, it defaults to one month ago. This function is used throughout the analytics system to filter data based on the selected timeframe.


6. Create API Routes

<?php

// routes/api.php


use App\Http\Controllers\AnalyticsTrackingController;

use App\Http\Controllers\AnalyticsDashboardController;

use Illuminate\Support\Facades\Route;


// Public tracking endpoints (CORS enabled)



analytics/track

Registers a route that listens for POST requests to /api/analytics/track.

When a request arrives, Laravel calls the track method on AnalyticsTrackingController.

Typical use: client sends pageview / event data (path, title, referrer, timestamp, user id/anon id). Because it’s POST, payload is in the request body (JSON or form data).


Route::post('/analytics/track', [AnalyticsTrackingController::class, 'track']);


analytics/time-spent

Calls updateTimeSpent on AnalyticsTrackingController.

Typical use: the client reports session duration / time-on-page or periodic heartbeats. Also a POST because you’re sending data to store/update.

Registers POST /api/analytics/time-spent.


Route::post('/analytics/time-spent', [AnalyticsTrackingController::class, 'updateTimeSpent']);


// Protected dashboard endpoints (requires authentication)

Route::middleware(['auth:sanctum'])->prefix('analytics')->group(function () {

    

    Overview

Route::get('/overview', [AnalyticsDashboardController::class, 'overview']); is a Laravel route definition that connects an HTTP GET request to a specific controller method. When a client or admin panel makes a request to the URL /api/analytics/overview, Laravel automatically triggers the overview() method inside the AnalyticsDashboardController. This method usually gathers high-level analytics data such as total visitors, pageviews, unique users, device statistics, or any summarized metrics needed for the dashboard’s overview section. Because this route is placed inside an auth:sanctum middleware group, it can only be accessed by authenticated users, ensuring that sensitive analytics information is protected and visible only to authorized administrators. This route essentially acts as the entry point for loading the main summary of your analytics dashboard.

    Route::get('/overview', [AnalyticsDashboardController::class, 'overview']);

    

    daily-traffic

 The route Route::get('/daily-traffic', [AnalyticsDashboardController::class, 'dailyTraffic']); defines an API endpoint that responds to GET requests made to /api/analytics/daily-traffic. When this URL is accessed, Laravel automatically calls the dailyTraffic() method inside the AnalyticsDashboardController. This method is typically responsible for generating and returning daily traffic analytics—such as the number of visitors, pageviews, or sessions recorded on each day. Because this route is placed inside an authentication-protected group using auth:sanctum, only authenticated admin users can access this data. This ensures that your daily traffic statistics remain secure and are only visible within the analytics dashboard.   

 Route::get('/daily-traffic', [AnalyticsDashboardController::class, 'dailyTraffic']); 


    Monthly-traffic

This route handles GET requests made to /api/analytics/monthly-traffic. When called, Laravel executes the monthlyTraffic() method from the AnalyticsDashboardController. This endpoint provides aggregated traffic statistics by month—showing patterns such as monthly growth, total visits per month, or long-term trends. This data is especially useful for analytics dashboards that visualize month-to-month performance.

    Route::get('/monthly-traffic', [AnalyticsDashboardController::class, 'monthlyTraffic']);

    

    Country-stats

This route registers a GET endpoint at /api/analytics/country-stats. When someone accesses this endpoint, Laravel calls the countryStats() method inside the AnalyticsDashboardController. That method usually compiles analytics data grouped by country—such as how many visitors came from each region—helping visualize global traffic distribution. Because this route sits behind Sanctum authentication, only logged-in and authorized users can access these geographic statistics.

    Route::get('/country-stats', [AnalyticsDashboardController::class, 'countryStats']);

    

    Most-visited-pages

Route::get('/most-visited-pages', [AnalyticsDashboardController::class, 'mostVisitedPages']); defines an API endpoint that returns the list of pages with the highest number of visits. When a client sends a GET request to /api/analytics/most-visited-pages, Laravel automatically triggers the mostVisitedPages() method inside the AnalyticsDashboardController. That method usually fetches analytics data—such as which pages users view the most, how many visits each page received, and possibly ranking or percentages. Because this route is inside the authenticated middleware group, only logged-in or authorized users (such as admin panel users) can access this data. This ensures the analytics information remains secure and visible only to authorized people.

    Route::get('/most-visited-pages', [AnalyticsDashboardController::class, 'mostVisitedPages']);

    

    exit-pages 

This route responds to a GET request at /api/analytics/exit-pages and invokes the exitPages() method inside the controller. It provides data about which pages users most frequently leave the site from. These insights are useful for identifying potential issues with pages that may cause users to drop off.   

    Route::get('/exit-pages', [AnalyticsDashboardController::class, 'exitPages']);



    

    Category-stats

Route::get('/category-stats', [AnalyticsDashboardController::class, 'categoryStats']);

This route returns metrics grouped by content category. When /api/analytics/category-stats is requested, categoryStats() compiles statistics like visits, conversions, or average engagement for each category (e.g., blog, product, support), enabling category-level comparison and strategic content decisio

    Route::get('/category-stats', [AnalyticsDashboardController::class, 'categoryStats']);

    

    Visitor-map

The route Route::get('/visitor-map', [AnalyticsDashboardController::class, 'visitorMap']); defines a GET endpoint in your Laravel API that is responsible for providing data used to visualize the geographical distribution of visitors on your site. When an authenticated request is made to /api/analytics/visitor-map, Laravel calls the visitorMap() method of the AnalyticsDashboardController. This method typically gathers location-based data such as visitor counts by country, region, or city, and returns it in a structured JSON format suitable for rendering a map or heatmap on the analytics dashboard. Since this route is protected by the auth:sanctum middleware, only authorized users can access it, ensuring that sensitive visitor location data is kept secure.

    Route::get('/visitor-map', [AnalyticsDashboardController::class, 'visitorMap']);

});



Frontend

Post a Comment

0 Comments