Install IssueCapture in Next.js
Add bug reporting to your Next.js application in 5 minutes. Works with App Router, Pages Router, and all versions of Next.js (13, 14, 15+).
Quick Summary
Prerequisites
- Next.js 13 or higher installed
- Jira Cloud account (Software or JSM)
- IssueCapture account (sign up free)
- Basic knowledge of Next.js
Step-by-Step Installation
Follow these steps to get up and running in minutes.
Get Your API Key
Sign up for IssueCapture and retrieve your widget API key from the dashboard
- Go to issuecapture.com/signup and create a free account
- Connect your Jira instance via OAuth
- Navigate to the Widgets page and create a new widget
- Copy your API key (starts with "ic_")
Add Environment Variable
Store your API key securely in .env.local
- Create .env.local in your project root (if it doesn't exist)
- Add NEXT_PUBLIC_ prefix to make it accessible in the browser
- Never commit this file to version control (add to .gitignore)
- Restart your dev server after adding environment variables
# .env.local
NEXT_PUBLIC_ISSUECAPTURE_API_KEY=ic_your_api_key_hereInstall in Root Layout (App Router)
Add IssueCapture to your root layout.tsx for site-wide availability
- Use Next.js Script component for optimized loading
- strategy="afterInteractive" loads after page becomes interactive
- The auto trigger creates a floating button automatically
- Widget is available on all pages in your app
- Works with Next.js 13, 14, 15+ and all React versions
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{children}
{/* IssueCapture Widget */}
<Script
src="https://issuecapture.com/widget.js"
strategy="afterInteractive"
onLoad={() => {
if (window.IssueCapture) {
window.IssueCapture.init({
apiKey: process.env.NEXT_PUBLIC_ISSUECAPTURE_API_KEY!,
trigger: 'auto', // Creates floating button
button: {
position: 'bottom-right',
text: 'Report Bug'
}
})
}
}}
/>
</body>
</html>
)
}Option: Custom Trigger Button
Use your own button instead of the auto-generated one
- Replace trigger: "auto" with a CSS selector
- The selector can target any element on the page
- Multiple elements can be targeted (e.g., ".report-bug-btn")
- The widget opens when the element is clicked
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{children}
{/* Your custom button */}
<button id="custom-bug-button" className="your-styles">
Report Issue
</button>
{/* IssueCapture Widget */}
<Script
src="https://issuecapture.com/widget.js"
strategy="afterInteractive"
onLoad={() => {
if (window.IssueCapture) {
window.IssueCapture.init({
apiKey: process.env.NEXT_PUBLIC_ISSUECAPTURE_API_KEY!,
trigger: '#custom-bug-button' // Use CSS selector
})
}
}}
/>
</body>
</html>
)
}Client Component Example
Open the widget programmatically from a Client Component
- Use window.IssueCapture.open() to open programmatically
- Use window.IssueCapture.close() to close programmatically
- Check if window.IssueCapture exists before calling methods
- Works with React 18 and React 19
- Add TypeScript declarations (see troubleshooting below)
// components/BugReportButton.tsx
'use client'
import { useState } from 'react'
export default function BugReportButton() {
const [isOpen, setIsOpen] = useState(false)
const openWidget = () => {
if (window.IssueCapture) {
window.IssueCapture.open()
setIsOpen(true)
}
}
const closeWidget = () => {
if (window.IssueCapture) {
window.IssueCapture.close()
setIsOpen(false)
}
}
return (
<button
onClick={openWidget}
className="px-4 py-2 bg-blue-600 text-white rounded"
>
Report Bug
</button>
)
}Set User Context (Optional)
Pre-fill user information for authenticated users
- Pre-fill reporter name and email for authenticated users
- Component field maps to Jira components (useful for routing)
- User data is included in the Jira issue description
- Works with async Server Components (Next.js 13.4+)
- This is optional but improves the developer experience
// app/layout.tsx
import Script from 'next/script'
import { auth } from '@/lib/auth' // Your auth library
export default async function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const session = await auth()
return (
<html lang="en">
<body>
{children}
<Script
src="https://issuecapture.com/widget.js"
strategy="afterInteractive"
onLoad={() => {
if (window.IssueCapture) {
window.IssueCapture.init({
apiKey: process.env.NEXT_PUBLIC_ISSUECAPTURE_API_KEY!,
trigger: 'auto',
user: {
name: session?.user?.name || "",
email: session?.user?.email || "",
component: 'Frontend' // Optional: Jira component
}
})
}
}}
/>
</body>
</html>
)
}Test the Integration
Verify IssueCapture is working correctly
- Start your dev server: npm run dev
- Open your app in the browser
- You should see the floating bug report button
- Click it and submit a test issue
- Check your Jira project for the created issue
- Open browser console and type: window.IssueCapture.isOpen()
Troubleshooting
Common integration issues and how to solve them.
TypeScript: Property 'IssueCapture' does not exist on type 'Window'
Add type declarations to your project (types/issuecapture.d.ts)
- Create a type declaration file in types/issuecapture.d.ts
- Declare the IssueCaptureAPI interface with init, open, close, isOpen, destroy methods
- Extend the Window interface with IssueCapture property
Widget not loading or button not appearing
- Check browser console for errors
- Verify API key is correct and starts with "ic_"
- Ensure NEXT_PUBLIC_ prefix is used in .env.local
- Restart dev server after changing environment variables
- Check that your domain is in the allowlist in IssueCapture dashboard
Domain allowlist errors when submitting issues (often shown as CORS)
- Go to IssueCapture dashboard → Widgets → Your Widget → Domains
- Add localhost:3000 for development
- Add your production domain (e.g., app.example.com)
Issues with Next.js 15 / React 19
- IssueCapture uses Shadow DOM, so it works independently of React version
- Clear .next cache if seeing unexpected behavior: rm -rf .next
- Script strategy="afterInteractive" is compatible with Turbopack
Pages Router (legacy)
- For Pages Router, add the script to _app.tsx instead of layout.tsx
- The same Script component and configuration works in both routers
- App Router is recommended for new projects
Ready to get started?
Sign up for a free account and start collecting bug reports in your Next.js app in minutes.