Overview
Add your Invent AI assistant to any Gatsby site. Perfect for static websites built with React and GraphQL.
Installation
Install React Helmet
npm install react-helmet gatsby-plugin-react-helmet
Configure gatsby-config.js
Add the plugin to your gatsby-config.js
: module . exports = {
plugins: [
'gatsby-plugin-react-helmet' ,
// ... other plugins
],
};
Create Assistant Component
// src/components/InventAssistant.tsx
import React from 'react' ;
interface InventAssistantProps {
assistantId : string ;
themeAppearance ?: 'auto' | 'light' | 'dark' ;
themeButtonBackgroundColor ?: string ;
themeButtonColor ?: string ;
userId ?: string ;
userName ?: string ;
userHash ?: string ;
userAvatar ?: string ;
}
const InventAssistant : React . FC < InventAssistantProps > = ({
assistantId ,
themeAppearance = 'auto' ,
themeButtonBackgroundColor ,
themeButtonColor ,
userId ,
userName ,
userHash ,
userAvatar ,
}) => {
return (
<>
< invent-assistant
assistant-id = { assistantId }
theme-appearance = { themeAppearance }
{ ... ( themeButtonBackgroundColor && {
'theme-button-background-color' : themeButtonBackgroundColor ,
}) }
{ ... ( themeButtonColor && {
'theme-button-color' : themeButtonColor ,
}) }
{ ... ( userId && { 'user-id' : userId }) }
{ ... ( userName && { 'user-name' : userName }) }
{ ... ( userHash && { 'user-hash' : userHash }) }
{ ... ( userAvatar && { 'user-avatar' : userAvatar }) }
/>
< script
type = "text/javascript"
src = "https://www.useinvent.com/button.js"
async
defer
/>
</>
);
};
export default InventAssistant ;
Add to Layout
// src/components/layout.tsx
import React from 'react' ;
import InventAssistant from './InventAssistant' ;
const Layout : React . FC <{ children : React . ReactNode }> = ({ children }) => {
return (
<>
< main > { children } </ main >
< InventAssistant assistantId = { process . env . GATSBY_INVENT_ASSISTANT_ID ! } />
</>
);
};
export default Layout ;
Add Environment Variable
Create .env.development
and .env.production
: GATSBY_INVENT_ASSISTANT_ID = ast_YOUR_ASSISTANT_ID
User Authentication
Security Requirement: When using any user-*
attributes (user-id
, user-name
, user-avatar
), you must also provide user-hash
. Both user-id
and user-hash
must be provided together, or neither should be provided. The user-hash
must be generated on your backend using HMAC-SHA256 with your assistant’s secret key. Never expose the secret key to the client.
Using Gatsby Functions (Serverless)
Gatsby Functions allow you to generate the hash server-side:
// src/api/user-hash.ts
import type { GatsbyFunctionRequest , GatsbyFunctionResponse } from 'gatsby' ;
import crypto from 'crypto' ;
export default function handler (
req : GatsbyFunctionRequest ,
res : GatsbyFunctionResponse
) {
// Get user from your auth system
const userId = req . headers [ 'x-user-id' ];
if ( ! userId ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
const secretKey = process . env . INVENT_SECRET_KEY ! ;
const userHash = crypto
. createHmac ( 'sha256' , secretKey )
. update ( userId as string )
. digest ( 'hex' );
return res . json ({
userId ,
userHash ,
});
}
Fetching User Data
// src/components/InventAssistantWrapper.tsx
import React , { useEffect , useState } from 'react' ;
import InventAssistant from './InventAssistant' ;
const InventAssistantWrapper : React . FC = () => {
const [ userData , setUserData ] = useState <{
userId ?: string ;
userName ?: string ;
userHash ?: string ;
userAvatar ?: string ;
} | null >( null );
useEffect (() => {
fetch ( '/api/user-hash' )
. then (( res ) => res . json ())
. then ( setUserData )
. catch ( console . error );
}, []);
return (
< InventAssistant
assistantId = { process . env . GATSBY_INVENT_ASSISTANT_ID ! }
{ ... userData }
/>
);
};
export default InventAssistantWrapper ;
GraphQL Integration
Pass content data to provide context:
// src/templates/blog-post.tsx
import React , { useEffect } from 'react' ;
import { graphql } from 'gatsby' ;
import Layout from '../components/layout' ;
const BlogPost : React . FC <{ data : any }> = ({ data }) => {
const post = data . markdownRemark ;
useEffect (() => {
if ( typeof window !== 'undefined' ) {
window . inventContext = {
pageType: 'blog-post' ,
title: post . frontmatter . title ,
author: post . frontmatter . author ,
category: post . frontmatter . category ,
};
}
}, [ post ]);
return (
< Layout >
< article >
< h1 > { post . frontmatter . title } </ h1 >
< div dangerouslySetInnerHTML = { { __html: post . html } } />
</ article >
</ Layout >
);
};
export const query = graphql `
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
html
frontmatter {
title
author
category
}
}
}
` ;
export default BlogPost ;
TypeScript Support
Add type declarations:
// src/types/invent-assistant.d.ts
declare namespace JSX {
interface IntrinsicElements {
'invent-assistant' : {
'assistant-id' : string ;
'theme-appearance' ?: 'auto' | 'light' | 'dark' ;
'theme-button-background-color' ?: string ;
'theme-button-color' ?: string ;
'user-id' ?: string ;
'user-name' ?: string ;
'user-hash' ?: string ;
'user-avatar' ?: string ;
};
}
}
interface Window {
inventContext ?: Record < string , any >;
}
Tips for Gatsby
Serverless Functions Use Gatsby Functions for hash generation
GraphQL Context Pass content data for better context
Static & Dynamic Works with SSG and DSG builds
Plugin Ecosystem Integrates with Gatsby plugins
Troubleshooting
Script loading multiple times
Solutions:
Check gatsby-browser.js for duplicate script logic
Use conditional to prevent duplicate loads
Clear .cache and public folders: gatsby clean
Environment variables not working
Solutions:
Prefix public variables with GATSBY_
Restart development server
Check .env files exist
Verify gatsby-config.js is reading variables
Solutions:
Ensure typeof window checks for SSR
Use dynamic imports if needed
Check all dependencies are installed
Clear cache: gatsby clean
Best Practices
Use Gatsby Functions for server-side operations
Always check for window
before accessing it
Store secret keys in .env
files (never commit)
Use GATSBY_
prefix only for public variables
Test both development and production builds