DEV Community

Custodia-Admin
Custodia-Admin

Posted on

How to Take Screenshots of Password-Protected Pages (With Session Cookies)

How to Take Screenshots of Password-Protected Pages (With Session Cookies)

You need to screenshot a protected page. Your dashboard. An admin panel. Paywalled content behind a login.

The problem: screenshot APIs don't have your login session. They see a redirect to /login instead of your dashboard.

The solution: pass your session cookies or Bearer token to the API.

Here's how to screenshot authenticated pages using the PageBolt API.

The Problem: Protected Pages Require Authentication

A raw API call to an authenticated page returns the login page:

curl -X POST https://api.pagebolt.dev/v1/screenshot \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/dashboard"}' \
  > screenshot.png

# Result: screenshot of login page, not dashboard
Enter fullscreen mode Exit fullscreen mode

The API doesn't have your cookies. It can't authenticate. It sees the login redirect.

You need to pass authentication data to the API.

Solution 1: Session Cookies

Extract your session cookie and pass it to the API:

// Get session cookie from your browser/app
// Example: "session_id=abc123def456; Path=/; HttpOnly"

const sessionCookie = 'session_id=abc123def456';

const payload = {
  url: 'https://example.com/dashboard',
  format: 'png',
  cookies: [
    {
      name: 'session_id',
      value: 'abc123def456',
      domain: 'example.com'
    }
  ]
};

const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});

const buffer = await response.arrayBuffer();
Enter fullscreen mode Exit fullscreen mode

That's it. The API authenticates using your cookie and returns the dashboard screenshot.

Real Example: Dashboard Screenshot with Session Cookie

// dashboard-screenshot.js
const https = require('https');
const fs = require('fs');

async function screenshotDashboard() {
  // 1. Your app's session cookie
  // In production, fetch this from your session store or database
  const sessionCookie = 'session_id=abc123xyz789; path=/; domain=example.com';

  // 2. Parse cookie
  const [name, value] = sessionCookie.split('=').map(s => s.trim());

  // 3. Send to PageBolt with cookie
  const payload = JSON.stringify({
    url: 'https://example.com/dashboard',
    format: 'png',
    width: 1920,
    height: 1080,
    fullPage: true,
    cookies: [
      {
        name: name,
        value: value.split(';')[0], // Remove path/domain suffix
        domain: 'example.com'
      }
    ]
  });

  const options = {
    hostname: 'api.pagebolt.dev',
    path: '/v1/screenshot',
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(payload)
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = Buffer.alloc(0);

      res.on('data', (chunk) => {
        data = Buffer.concat([data, chunk]);
      });

      res.on('end', () => {
        if (res.statusCode === 200) {
          fs.writeFileSync('dashboard.png', data);
          console.log('✓ Dashboard screenshot saved');
          resolve(data);
        } else {
          reject(new Error(`API error ${res.statusCode}`));
        }
      });
    });

    req.on('error', reject);
    req.write(payload);
    req.end();
  });
}

screenshotDashboard().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Solution 2: Bearer Token Authentication

If your API uses Bearer token auth instead of cookies:

const payload = {
  url: 'https://api.example.com/admin',
  format: 'png',
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
  }
};

const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});
Enter fullscreen mode Exit fullscreen mode

Real Example: JWT Bearer Token

// api-screenshot-jwt.js
const https = require('https');
const fs = require('fs');

async function screenshotProtectedAPI() {
  // Your JWT token (get from login endpoint or session store)
  const jwtToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';

  const payload = JSON.stringify({
    url: 'https://api.example.com/admin-dashboard',
    format: 'png',
    width: 1280,
    height: 720,
    headers: {
      'Authorization': `Bearer ${jwtToken}`,
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    }
  });

  const options = {
    hostname: 'api.pagebolt.dev',
    path: '/v1/screenshot',
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(payload)
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = Buffer.alloc(0);

      res.on('data', (chunk) => {
        data = Buffer.concat([data, chunk]);
      });

      res.on('end', () => {
        if (res.statusCode === 200) {
          fs.writeFileSync('admin-dashboard.png', data);
          console.log('✓ Admin dashboard screenshot saved');
          resolve(data);
        } else {
          reject(new Error(`API error ${res.statusCode}`));
        }
      });
    });

    req.on('error', reject);
    req.write(payload);
    req.end();
  });
}

screenshotProtectedAPI().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Multiple Cookies Example

If your app uses multiple cookies:

const payload = {
  url: 'https://example.com/dashboard',
  format: 'png',
  cookies: [
    {
      name: 'session_id',
      value: 'abc123xyz',
      domain: 'example.com'
    },
    {
      name: 'user_preferences',
      value: 'theme=dark&lang=en',
      domain: 'example.com'
    },
    {
      name: '_ga',
      value: 'GA1.2.1234567890.1234567890',
      domain: 'example.com'
    }
  ]
};
Enter fullscreen mode Exit fullscreen mode

Extracting Cookies from Your Browser

Chrome DevTools

  1. Open your app in Chrome
  2. Open DevTools: F12 → Application tab
  3. Left sidebar → Cookies → select your domain
  4. Copy cookie names and values

Programmatic Extraction

// Node.js: Extract cookies from Puppeteer session
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/login');

// (perform login steps)

const cookies = await page.cookies();
console.log(JSON.stringify(cookies, null, 2));
// Output:
// [
//   {
//     "name": "session_id",
//     "value": "abc123xyz",
//     "domain": "example.com",
//     "path": "/",
//     "httpOnly": true
//   }
// ]
Enter fullscreen mode Exit fullscreen mode

Production: Store Auth Tokens in Environment Variables

Never hardcode tokens. Use environment variables:

# .env
PAGEBOLT_API_KEY=YOUR_API_KEY
AUTH_SESSION_COOKIE=session_id=abc123xyz
AUTH_BEARER_TOKEN=eyJhbGciOiJIUzI1NiI...
Enter fullscreen mode Exit fullscreen mode
// Use in code
const sessionCookie = process.env.AUTH_SESSION_COOKIE;
const bearerToken = process.env.AUTH_BEARER_TOKEN;
Enter fullscreen mode Exit fullscreen mode

Handle Token Expiration

Tokens expire. Handle this gracefully:

async function screenshotWithAuthRefresh(url, getAuthToken) {
  let attempts = 0;
  const maxAttempts = 2;

  while (attempts < maxAttempts) {
    try {
      const authToken = await getAuthToken();

      const payload = {
        url: url,
        format: 'png',
        headers: {
          'Authorization': `Bearer ${authToken}`
        }
      };

      const response = await fetch('https://api.pagebolt.dev/v1/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });

      if (response.status === 401) {
        console.log('Auth token expired, refreshing...');
        attempts++;
        continue; // Retry with new token
      }

      if (response.ok) {
        return await response.arrayBuffer();
      } else {
        throw new Error(`API error ${response.status}`);
      }
    } catch (error) {
      if (attempts < maxAttempts - 1) {
        attempts++;
      } else {
        throw error;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

Monitoring Dashboard Screenshots (Daily)

// monitor-dashboard.js
const cron = require('node-cron');

// Run every day at 9 AM
cron.schedule('0 9 * * *', async () => {
  const token = await getLatestSessionToken(); // Your auth logic

  const payload = {
    url: 'https://example.com/dashboard',
    format: 'png',
    headers: {
      'Authorization': `Bearer ${token}`
    }
  };

  const screenshot = await takeScreenshot(payload);
  await saveToS3(screenshot, `dashboards/${new Date().toISOString()}.png`);
});
Enter fullscreen mode Exit fullscreen mode

Admin Panel Alerts

// admin-panel-alert.js
async function checkAdminPanel() {
  const token = await getAdminToken();

  const screenshot = await takeScreenshot({
    url: 'https://internal.example.com/admin',
    format: 'png',
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  // Compare against baseline
  const diff = await compareImages(screenshot, baselineScreenshot);

  if (diff > threshold) {
    await sendAlert('Admin panel changed unexpectedly');
  }
}
Enter fullscreen mode Exit fullscreen mode

Security Best Practices

  1. Never log tokens — Don't print auth headers to console in production
  2. Use environment variables — Store tokens in .env or secret management (AWS Secrets Manager, etc.)
  3. Rotate tokens regularly — Don't use the same token forever
  4. Use short-lived tokens — Prefer JWTs with expiration over long-lived session cookies
  5. HTTPS only — Always use HTTPS when passing auth data
  6. Validate responses — Check status codes; don't blindly assume success

Key Takeaways

  1. Pass cookies via the APIcookies parameter accepts name/value pairs
  2. Use Bearer tokens for APIs — Pass in headers.Authorization header
  3. Support both auth methods — Cookies for web sessions, tokens for APIs
  4. Handle expiration — Refresh tokens and retry on 401
  5. Secure your tokens — Use environment variables, rotate regularly

Next step: Get your free API key at pagebolt.dev. 100 requests/month, no credit card required.

Try it free: https://pagebolt.dev/pricing

Top comments (0)