Request Detection

Detect Gale requests and respond differently based on request type.

Overview

Gale requests are identified by special HTTP headers. Detecting these allows you to:

  • Return different responses for Gale vs regular HTTP requests
  • Conditionally render Blade sections
  • Handle navigation requests differently
  • Build hybrid routes that work with and without JavaScript

How Gale Identifies Requests

When Alpine Gale makes a request, it sends a Gale-Request header. For navigation requests, it also sends Gale-Navigate and optionally Gale-Navigate-Key headers.

isGale()

The primary method to check if the current request is a Gale request:

1if (request()->isGale()) {
2    // This is a Gale SSE request
3    return gale()->state('updated', true);
4}
5
6// Regular HTTP request
7return view('page');

isGaleNavigate()

Check if the request is a navigation request (triggered by x-navigate or $navigate()):

 1// Check if it's any navigation request
 2if (request()->isGaleNavigate()) {
 3    // Handle navigation
 4}
 5
 6// Check for a specific navigation key
 7if (request()->isGaleNavigate('sidebar')) {
 8    // Only update sidebar content
 9}
10
11// Check for multiple possible keys
12if (request()->isGaleNavigate(['sidebar', 'content'])) {
13    // Handle either sidebar or content navigation
14}
Navigation Keys
Navigation keys allow different parts of your page to navigate independently. For example, a sidebar can update without affecting the main content. See Frontend Navigation for details.

Get the raw navigation key(s) from the request:

1// Get the raw key string (e.g., "sidebar" or "sidebar,content")
2$keyString = request()->galeNavigateKey();
3
4// Get keys as an array
5$keys = request()->galeNavigateKeys();
6// ['sidebar', 'content']

Blade Directive

Use @ifgale to conditionally render content in Blade templates:

 1@ifgale
 2    
 3    <div id="partial-content">
 4        Updated content here
 5    </div>
 6@else
 7    
 8    <!DOCTYPE html>
 9    <html>
10    <head>...</head>
11    <body>
12        <div id="partial-content">
13            Initial content here
14        </div>
15    </body>
16    </html>
17@endifgale

This is useful for returning partial HTML for Gale requests while still supporting full page loads for direct URL visits or when JavaScript is disabled.

Conditional Response Methods

GaleResponse provides fluent methods for conditional execution:

whenGale()

1return gale()
2    ->whenGale(function ($gale) {
3        // Only executed for Gale requests
4        return $gale->state('partial', true);
5    }, function ($gale) {
6        // Fallback for non-Gale requests (optional)
7        return $gale->web(view('full-page'));
8    });

whenNotGale()

1return gale()
2    ->state('data', $data)
3    ->whenNotGale(function ($gale) {
4        // Only for regular HTTP requests
5        return $gale->web(view('page'));
6    });

whenGaleNavigate()

1return gale()
2    ->whenGaleNavigate('sidebar', function ($gale) {
3        // Only when navigating with key 'sidebar'
4        return $gale->fragment('layouts.app', 'sidebar', $data);
5    })
6    ->whenGaleNavigate('content', function ($gale) {
7        // Only when navigating with key 'content'
8        return $gale->fragment('layouts.app', 'content', $data);
9    });

Practical Examples

Hybrid Route

A route that works for both Gale and regular requests:

 1public function index()
 2{
 3    $posts = Post::latest()->paginate(10);
 4
 5    return gale()
 6        ->state('posts', $posts->items())
 7        ->state('pagination', [
 8            'current' => $posts->currentPage(),
 9            'total' => $posts->lastPage(),
10        ])
11        ->view('posts.list', compact('posts'), web: true);
12}
Tip
The web: true option on view() automatically returns the view for non-Gale requests, eliminating the need for manual isGale() checks.

Partial Updates

Return only the changed portion for Gale requests:

 1public function search(Request $request)
 2{
 3    $results = Product::search($request->state('query'))->get();
 4
 5    if (request()->isGale()) {
 6        return gale()
 7            ->state('results', $results)
 8            ->fragment('products.index', 'results-list', compact('results'));
 9    }
10
11    return view('products.index', compact('results'));
12}

Split Navigation

Handle independent navigation regions:

 1public function show(Category $category)
 2{
 3    $products = $category->products()->paginate(12);
 4
 5    // Sidebar navigation - only update sidebar
 6    if (request()->isGaleNavigate('sidebar')) {
 7        return gale()->fragment('shop.layout', 'sidebar', [
 8            'categories' => Category::all(),
 9            'active' => $category->id,
10        ]);
11    }
12
13    // Main content navigation
14    if (request()->isGaleNavigate('content')) {
15        return gale()
16            ->state('products', $products->items())
17            ->fragment('shop.layout', 'product-grid', compact('products'));
18    }
19
20    // Full page load
21    return view('shop.category', compact('category', 'products'));
22}

Quick Reference

Method/Directive Description
request()->isGale() Returns true for Gale requests
request()->isGaleNavigate() Returns true for navigation requests
request()->isGaleNavigate('key') Check for specific navigation key
request()->galeNavigateKey() Get navigation key string
request()->galeNavigateKeys() Get navigation keys as array
@ifgale / @endifgale Blade conditional for Gale requests
gale()->whenGale(cb, fallback) Execute callback for Gale requests
gale()->whenNotGale(cb) Execute callback for non-Gale requests
gale()->whenGaleNavigate(key, cb) Execute callback for specific navigation key

On this page