Screenshot API Integration with Vue.js: Complete Guide

Vue.js applications often need to generate screenshots of pages, export dashboard views as images, or capture user-generated content. Rather than shipping a headless browser with your backend, SnapAPI provides a simple REST API that Vue.js apps can call directly to capture any URL. This guide covers every integration pattern from simple composables to Pinia store integration.

Basic Vue Composable

Create a reusable composable at src/composables/useSnapAPI.js:

import { ref } from "vue"

export function useSnapAPI() {
  const loading = ref(false)
  const error = ref(null)

  async function screenshot(url, options = {}) {
    loading.value = true
    error.value = null
    try {
      const params = new URLSearchParams({
        access_key: import.meta.env.VITE_SNAPAPI_KEY,
        url,
        response_type: "json",
        ...options
      })
      const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
      if (!res.ok) throw new Error("SnapAPI error " + res.status)
      const data = await res.json()
      return data.url
    } catch (e) {
      error.value = e.message
      return null
    } finally {
      loading.value = false
    }
  }

  return { screenshot, loading, error }
}

Screenshot Button Component

Use the composable in a Vue component that lets users capture the current page:

<template>
  <div>
    <button @click="capture" :disabled="loading">
      {{ loading ? "Capturing..." : "Download Screenshot" }}
    </button>
    <img v-if="imgUrl" :src="imgUrl" alt="Screenshot" />
    <p v-if="error" class="error">{{ error }}</p>
  </div>
</template>

<script setup>
import { ref } from "vue"
import { useSnapAPI } from "@/composables/useSnapAPI"

const { screenshot, loading, error } = useSnapAPI()
const imgUrl = ref(null)

async function capture() {
  imgUrl.value = await screenshot(window.location.href, { width: 1280, full_page: true })
}
</script>

Pinia Store for Screenshot Management

import { defineStore } from "pinia"

export const useScreenshotStore = defineStore("screenshots", {
  state: () => ({ captures: [], loading: false, error: null }),
  actions: {
    async capture(url, label) {
      this.loading = true
      const params = new URLSearchParams({
        access_key: import.meta.env.VITE_SNAPAPI_KEY,
        url, response_type: "json", width: 1280
      })
      const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
      const data = await res.json()
      this.captures.push({ url, label, imgUrl: data.url, capturedAt: new Date() })
      this.loading = false
    }
  }
})

Nuxt.js Server-Side Integration

For Nuxt.js applications, keep the API key server-side using a server route to proxy SnapAPI calls. Create server/api/screenshot.get.js:

export default defineEventHandler(async (event) => {
  const { url, ...opts } = getQuery(event)
  if (!url) throw createError({ statusCode: 400, message: "url required" })
  const config = useRuntimeConfig()
  const params = new URLSearchParams({
    access_key: config.snapApiKey, url, response_type: "json", ...opts
  })
  const res = await $fetch(`https://snapapi.pics/api/screenshot?${params}`)
  return res
})

In nuxt.config.ts add your key to runtimeConfig:

export default defineNuxtConfig({
  runtimeConfig: {
    snapApiKey: process.env.SNAPAPI_KEY,
    public: {}
  }
})

PDF Export from Vue Dashboard

Export any authenticated dashboard view as a PDF by proxying the request server-side with session credentials:

// server/api/export-pdf.post.js
export default defineEventHandler(async (event) => {
  const { dashboardUrl, sessionCookie } = await readBody(event)
  const config = useRuntimeConfig()
  const params = new URLSearchParams({
    access_key: config.snapApiKey,
    url: dashboardUrl,
    format: "pdf",
    headers: JSON.stringify({ Cookie: sessionCookie })
  })
  const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
  const buffer = await res.arrayBuffer()
  setResponseHeader(event, "Content-Type", "application/pdf")
  return buffer
})

Error Handling and Retry Logic

Add retry logic to your composable for production resilience. Network hiccups and occasional API timeouts are a reality in any integration. A simple retry with exponential backoff handles transient failures gracefully:

async function screenshotWithRetry(url, options = {}, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await screenshot(url, options)
    } catch (e) {
      if (i === attempts - 1) throw e
      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)))
    }
  }
}

Environment Configuration

Store your SnapAPI key in a .env file at your project root and reference it via import.meta.env.VITE_SNAPAPI_KEY in Vue components. Never commit .env files to version control. For Nuxt.js, use the runtimeConfig server-side approach shown above to keep the key fully server-side and out of the browser bundle. For Vue SPA deployments on Vercel or Netlify, configure the environment variable in your project settings dashboard and it will be available at build time.

Get Started Free

SnapAPI offers 200 screenshot API calls per month on the free tier with no credit card. Create your account, copy your API key into your .env file, and your first Vue.js screenshot integration can be working within the hour. Paid plans start at $19 per month for 5,000 screenshots and scale to custom enterprise tiers.

Get Free API Key

Advanced Vue.js Screenshot Patterns

Once the basic composable is working, Vue.js applications can build more sophisticated screenshot workflows that take advantage of Vue's reactivity system, component architecture, and ecosystem integrations. This section covers advanced patterns for production Vue apps.

Vue Router Integration for Dynamic Captures

If your Vue app uses Vue Router and you need to capture specific route views, you can build the full URL from the router's resolve method and pass it to SnapAPI. This is particularly useful for generating OG images for dynamic routes where each route has unique content:

import { useRouter } from "vue-router"

const router = useRouter()

async function captureRoute(routeName, params) {
  const resolved = router.resolve({ name: routeName, params })
  const fullUrl = window.location.origin + resolved.href
  return await screenshot(fullUrl, { width: 1200, height: 630 })
}

Vuex Store Integration

For Vue 2 applications using Vuex, organize screenshot state as a Vuex module:

const screenshotModule = {
  namespaced: true,
  state: () => ({ captures: {}, loading: false }),
  mutations: {
    SET_CAPTURE(state, { key, url }) { state.captures[key] = url },
    SET_LOADING(state, val) { state.loading = val }
  },
  actions: {
    async capture({ commit }, { url, key }) {
      commit("SET_LOADING", true)
      const params = new URLSearchParams({ access_key: process.env.VUE_APP_SNAPAPI_KEY,
        url, response_type: "json" })
      const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
      const data = await res.json()
      commit("SET_CAPTURE", { key, url: data.url })
      commit("SET_LOADING", false)
    }
  }
}

Vue Test Utils Mocking

Mock the SnapAPI fetch call in your Vitest or Jest tests to avoid real API calls during the test suite:

import { mount } from "@vue/test-utils"
import { vi } from "vitest"
import ScreenshotButton from "./ScreenshotButton.vue"

vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
  ok: true,
  json: () => Promise.resolve({ url: "https://cdn.example.com/shot.png" })
}))

test("captures and displays screenshot", async () => {
  const wrapper = mount(ScreenshotButton)
  await wrapper.find("button").trigger("click")
  await nextTick()
  expect(wrapper.find("img").attributes("src")).toBe("https://cdn.example.com/shot.png")
})

Vite Environment Configuration

Configure your SnapAPI key for different environments using Vite's built-in environment variable support. Create .env.development and .env.production files at your project root. Prefix variables with VITE_ to expose them to the browser bundle, or keep them as server-only variables in your Nuxt runtimeConfig for maximum key security. Never commit .env files to version control. Add them to .gitignore and document the required variables in your project README so new team members know what environment variables to configure.

Performance Considerations

Screenshot API calls take 2 to 8 seconds depending on page complexity. Always show a loading state in your Vue component during the capture. For user-initiated captures, disable the trigger button while loading to prevent duplicate requests. Cache capture results in your Pinia store or Vuex state keyed by URL so that repeated captures of the same URL within a session return the cached result immediately without another API call. Set a reasonable cache TTL based on how frequently your target pages update.

Common Questions about Vue.js and SnapAPI

Can SnapAPI capture my Vue SPA after client-side rendering completes? Yes. SnapAPI uses Playwright with Chromium under the hood and waits for the page to fully load before capturing. Use the wait_until parameter set to networkidle for SPAs that fetch data after initial render, or use the delay parameter to add a fixed wait after load. This ensures your Vue components have rendered their final state before the screenshot is taken. Can I capture a Vue component rather than a full page? SnapAPI captures full pages by URL. To capture a specific component, create a dedicated route in Vue Router that renders only that component, then pass the route URL to SnapAPI with an appropriate viewport size. This is the recommended pattern for generating component-level screenshots for documentation or design system purposes. Does SnapAPI work with Vue 2 and Vue 3? The API itself is framework-agnostic, so it works with any Vue version. The composable pattern shown in this guide uses the Composition API from Vue 3, but the underlying fetch call works identically in Vue 2 Options API. For Vue 2, use the Vuex module pattern shown in the advanced section rather than Pinia, which is the recommended state management library for Vue 3. Get started for free at snapapi.pics with 200 captures per month, no credit card required.

Ready to Get Started?

SnapAPI is live and processing screenshots for teams around the world right now. Create your free account and get your API key in under two minutes. No credit card required. The free tier includes 200 screenshots per month and full access to every API feature including screenshot, scrape, extract, PDF generation, and full-page capture. When you are ready to scale beyond the free tier, upgrade to a paid plan in your dashboard with no sales call required. Paid plans activate instantly and your rate limits increase immediately. The $19 per month plan covers most startup and small team use cases with 5,000 screenshots per month. The $79 per month plan at 50,000 screenshots per month is designed for production workloads at growing companies. Custom enterprise plans with dedicated infrastructure, SLAs, and optional private cloud deployment are available for organizations with specific requirements. Reach out through the contact page to discuss enterprise options. We respond to all enterprise inquiries within one business day.