Skip to main content

Preview Channels

Test and share your changes before going live. Preview channels create temporary, shareable URLs perfect for stakeholder reviews, QA testing, and feature validation.

What Are Preview Channels?​

Preview channels are temporary hosting environments that:

  • Create unique URLs for testing
  • Run alongside your production site
  • Expire automatically (configurable)
  • Perfect for pull request previews
  • Support all Hosting features

Example URL: your-project--channel-name-randomhash.web.app

Creating Preview Channels​

Basic Usage​

# Deploy to a preview channel
firebase hosting:channel:deploy preview

# Output:
# βœ” Hosting URL: https://myapp--preview-x8yn3k.web.app
# βœ” Channel URL (expires 2024-12-15): https://myapp--preview-x8yn3k.web.app

Named Channels​

Use descriptive names for better organization:

# Feature-specific channel
firebase hosting:channel:deploy new-checkout-flow

# Version-specific channel
firebase hosting:channel:deploy v2-0-0-beta

# PR-specific channel
firebase hosting:channel:deploy pr-123

Setting Expiration​

# Expires in 7 days (default)
firebase hosting:channel:deploy preview

# Expires in 30 days
firebase hosting:channel:deploy preview --expires 30d

# Expires in 12 hours
firebase hosting:channel:deploy preview --expires 12h

# Expires on specific date
firebase hosting:channel:deploy preview --expires 2024-12-31

Managing Preview Channels​

List Active Channels​

firebase hosting:channel:list

# Output:
# β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
# β”‚ Channel ID β”‚ URL β”‚ Expiration β”‚
# β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
# β”‚ preview β”‚ myapp--preview-x8yn3k.web.app β”‚ Dec 15, 2024 β”‚
# β”‚ feature-authβ”‚ myapp--feature-auth-a3b4c5.web.app β”‚ Dec 20, 2024 β”‚
# β”‚ pr-456 β”‚ myapp--pr-456-d6e7f8.web.app β”‚ Dec 18, 2024 β”‚
# β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Open Channel in Browser​

# Open specific channel
firebase hosting:channel:open preview

# Opens default browser to channel URL

Delete Channels​

# Delete specific channel
firebase hosting:channel:delete preview

# Delete with confirmation skip
firebase hosting:channel:delete preview --force

CI/CD Integration​

GitHub Actions​

name: Preview Channel on PR
on:
pull_request:
types: [opened, synchronize]

jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install and Build
run: |
npm ci
npm run build

- name: Deploy Preview
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: '${{ secrets.GITHUB_TOKEN }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT }}'
channelId: pr-${{ github.event.number }}
expires: 7d

- name: Comment PR
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'πŸš€ Preview deployed to: ${{ steps.deploy.outputs.url }}'
})

GitLab CI​

preview:
stage: deploy
script:
- npm ci
- npm run build
- firebase hosting:channel:deploy merge-request-$CI_MERGE_REQUEST_IID --expires 7d
environment:
name: preview/$CI_MERGE_REQUEST_IID
url: https://your-project--merge-request-$CI_MERGE_REQUEST_IID-*.web.app
only:
- merge_requests

Bitbucket Pipelines​

pipelines:
pull-requests:
'**':
- step:
name: Deploy Preview
script:
- npm ci
- npm run build
- firebase hosting:channel:deploy pr-$BITBUCKET_PR_ID --expires 7d --token $FIREBASE_TOKEN
- echo "Preview URL available in Firebase Console"

Advanced Usage​

Multi-Site Preview Channels​

# Deploy specific site to preview
firebase hosting:channel:deploy preview --only hosting:app
firebase hosting:channel:deploy preview --only hosting:blog

# Deploy multiple sites
firebase hosting:channel:deploy preview --only hosting:app,hosting:blog

Channel Cloning​

# Clone preview to another channel
firebase hosting:clone SOURCE:preview TARGET:qa-review

# Promote preview to production
firebase hosting:clone SOURCE:preview TARGET:live

Environment-Specific Builds​

// package.json
{
"scripts": {
"build:preview": "REACT_APP_ENV=preview npm run build",
"build:production": "REACT_APP_ENV=production npm run build",
"deploy:preview": "npm run build:preview && firebase hosting:channel:deploy preview",
"deploy:production": "npm run build:production && firebase deploy --only hosting"
}
}
// In your app
const API_URL = process.env.REACT_APP_ENV === 'preview'
? 'https://api-staging.example.com'
: 'https://api.example.com';

Testing Strategies​

QA Testing Workflow​

  1. Deploy to preview channel

    firebase hosting:channel:deploy qa-sprint-15 --expires 14d
  2. Share with QA team

    • Send preview URL
    • Include test credentials
    • Note expiration date
  3. Iterate on feedback

    # Redeploy same channel with fixes
    firebase hosting:channel:deploy qa-sprint-15
  4. Promote when approved

    firebase hosting:clone myapp:qa-sprint-15 myapp:live

A/B Testing​

// Simple client-side A/B test using preview channels
const isTestGroup = Math.random() < 0.5;
const baseUrl = isTestGroup
? 'https://myapp--new-design-x8yn3k.web.app'
: 'https://myapp.web.app';

// Track metrics for each version
analytics.track('page_view', {
version: isTestGroup ? 'new-design' : 'current'
});

Feature Flags with Preview Channels​

// feature-flags.js
const FEATURES = {
newCheckout: window.location.hostname.includes('--new-checkout-'),
darkMode: window.location.hostname.includes('--dark-mode-'),
betaFeatures: window.location.hostname.includes('--beta-')
};

// Usage
if (FEATURES.newCheckout) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}

Collaboration Features​

Stakeholder Reviews​

Create dedicated channels for different stakeholders:

# For design review
firebase hosting:channel:deploy design-review --expires 7d

# For client preview
firebase hosting:channel:deploy client-demo --expires 30d

# For internal testing
firebase hosting:channel:deploy internal-qa --expires 3d

Feedback Collection​

Embed feedback tools in preview channels:

<!-- Only show in preview channels -->
<script>
if (window.location.hostname.includes('--')) {
// Load feedback widget
const script = document.createElement('script');
script.src = 'https://feedback-tool.com/widget.js';
document.head.appendChild(script);
}
</script>

Performance Testing​

Load Testing Preview Channels​

# Deploy performance test version
firebase hosting:channel:deploy perf-test --expires 1d

# Run load tests against preview URL
artillery quick --count 100 --num 10 \
https://myapp--perf-test-x8yn3k.web.app/

Lighthouse CI​

# .github/workflows/lighthouse.yml
- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
${{ steps.deploy.outputs.url }}
${{ steps.deploy.outputs.url }}/products
${{ steps.deploy.outputs.url }}/checkout
uploadArtifacts: true

Security Considerations​

Access Control​

Preview channels are publicly accessible. For sensitive previews:

  1. Use obscure channel names

    firebase hosting:channel:deploy $(openssl rand -hex 12)
  2. Implement client-side auth

    // Simple password protection
    if (window.location.hostname.includes('--')) {
    const password = prompt('Enter preview password:');
    if (password !== 'SECRET_PREVIEW_PASS') {
    window.location.href = 'https://example.com';
    }
    }
  3. Short expiration times

    firebase hosting:channel:deploy sensitive-preview --expires 1h

Data Protection​

// Use different data in previews
const isPreview = window.location.hostname.includes('--');
const API_ENDPOINT = isPreview
? 'https://api-staging.example.com' // Test data
: 'https://api.example.com'; // Production data

Troubleshooting​

Common Issues​

IssueCauseSolution
"Channel not found"Channel expiredRedeploy with new channel
"Permission denied"Not authenticatedRun firebase login
URL not updatingBrowser cacheHard refresh (Ctrl+F5)
Build differencesEnv variablesCheck build configuration
Slow deploymentsLarge filesOptimize assets

Debug Commands​

# Check channel details
firebase hosting:channel:list

# View deployment logs
firebase hosting:channel:deploy preview --debug

# Compare with production
diff -r ./build ./build-production

Best Practices​

1. Naming Conventions​

# Good channel names
pr-123 # Pull request number
feature-auth # Feature name
v2-beta # Version
sprint-15 # Sprint number
client-review # Purpose

# Avoid
test # Too generic
preview # Not descriptive
john-test # Personal names

2. Cleanup Strategy​

# Automated cleanup script
#!/bin/bash
firebase hosting:channel:list --json | \
jq -r '.result[].name' | \
grep -E '^pr-[0-9]+$' | \
xargs -I {} firebase hosting:channel:delete {} --force

3. Documentation​

Always document preview channels in PRs:

## Preview Channel

πŸš€ **Preview URL**: https://myapp--pr-123-x8yn3k.web.app

**Expires**: Dec 31, 2024

**What to test**:
- [ ] New checkout flow
- [ ] Mobile responsive design
- [ ] Payment integration

**Known issues**:
- Analytics disabled in preview
- Using staging API endpoints

Cost Optimization​

Preview Channel Costs​

  • Storage: Counts toward 10GB limit
  • Bandwidth: Standard rates apply
  • Channels: No per-channel cost

Cost-Saving Tips​

  1. Set appropriate expiration

    # Short-lived for quick reviews
    --expires 1d

    # Longer for QA cycles
    --expires 7d
  2. Clean up regularly

    # Delete after PR merge
    firebase hosting:channel:delete pr-$PR_NUMBER
  3. Share channels

    • Reuse channels for similar features
    • Update existing channels vs creating new

Next Steps​


Pro Tip: Make preview channels part of your standard workflow. They're free to create and invaluable for catching issues before production. Every PR should have a preview! πŸš€