Skip to main content
Installing Vortex invitation widgets in your application involves adding a snippet of code for each widget. Add the snippet wherever you want to render the given invitation widget. If you’re building a standalone implementation (i.e., not mounting the widget inside an existing modal), you’re responsible for providing the container markup into which the vortex component will render. In other words, create the HTML element where you want the widget to appear, then paste your widget code snippet. Although widgetId is technically the only required parameter, both user and group are effectively required for most customers and there are others parameters detailed below that you will more than likely need to populate.
<VortexInvite
  widgetId={"ad968b65-f738-4b3b-957b-c3599773d09a"}
  user={}
  group={}
/>

widgetId

required A widget’s ID can also be found on the Install Client tab, in the code snippet.
widgetId={"aa9ebe43-e565-4299-b2b9-5d01018506ac"}

user

required This parameter is used to provide information about the current user (i.e., the inviter). In your staging and production environments you’ll need to send this via a signed JWT (see JSON Web Tokens). In your development environment, however, you can send unsigned JSON in the following format.
const unsignedUserData = { userId, identifiers: [{type: 'email', value: 'sally@acme.com'}], groups: [{ id: 'someId', type: 'workspace', name: 'Acme Workspace' }]};
You can also omit the parameter entirely in development, in which case mock user data will be used in your invitations.

group

required for most customers Although optional, the vast majority of Vortex customers will have a group associated with all invitations, and that group determines the uniqueness of your invitations. For example, a service like Slack groups customers into workspaces, and invitations to join Slack are unique per workspace. Three different people may invite sara@acme.com to join three different Slack workspaces. That email address only has to represent a unique invitation within each workspace. If Slack were using Vortex, every invitation to a workspace would include the ID of the given workspace passed in on this group parameter. Your service may have multiple groupings. For example, Trello has workspaces, but also has the concept of boards that are owned by a workspace. People can be invited to a workspace, but they can also be invited at the board level. They can even be invited to multiple boards within a workspace. If Trello were using Vortex, the group ID passed in would represent a workspace ID for invitations to a workspace, or a board ID for invitations to a board. While the above examples are both B2B services, the group concept applies to B2C services as well. On Airbnb, people are invited to a trip, and the group ID would be that of the trip. On social networks and other community sites, where people are invited to be your contact/friend, the group ID would represent the user ID of the inviter. For example, sara@gmail.com could be invited by both Jason and Tracy to join Goodreads, and the group ID passed in on those invitations would be Jason’s and Sara’s user IDs respectively. The only scenario under which your invitations would not involve some kind of group would be if your service had absolutely no grouping of users or connectivity between users. The following information can be passed in for a group.
  • groupId (required) - The internal ID of the group associated with the invitation. As noted in the examples above, this could be workspace, organization, team, board, project, etc. Or in the case of a community site, where people are being invited as contacts, it would be the user ID of the inviter. Although technically not required, most service’s invitations are associated with some form of grouping. Unless your service has no grouping of users and no connectivity between them, you should populate ID.
  • type (required) - This is the identifier for the type of group. For example, “workspace”, “board”, “organization”, “board”, “project”, etc. This value allows you to identify the type of invitation when an invitee is directed to your service. It also allows you to meaningfully filter your analytics.
  • name (optional) - The actual name of the given group associated with the invitation. For example, the name of the workspace, organization, team, etc. This is optional, but it is useful for making your Power Groups analytics report (i.e., the groups generating the most invitations and acceptances) more readable. In the absence of group names, IDs will be displayed.
group={{ id: "f1234567-89ab-cdef-0123-456789abcdef", type: "workspace", name: "Acme Workspace" }}

userEmailsInGroup

If the number of members in a group isn’t large, you can send them all via this parameter so that Vortex can validate that the person being invited isn’t already a member. If the number of members is too large to pass all of them in here, use the subsequent emailValidationFunction parameter instead.
userEmailsInGrouping={["sally@acme.com", "alex@acme.com", "bob@acme.com"]}

emailValidationFunction

For large groupings, where sending all members in userEmailsInGrouping isn’t practical, you can provide your own validation function. For example:
const emailValidationFunction = (email: string): boolean | null => {
  return email.includes('@');
};

or

const emailValidationFunction = async (emails: string[]): Promise<{ 
    isValid: boolean, 
    invalidEmails?: string[], 
    errorMessage?: string }> => {
  const result = await someAsyncCheck(email);
  return result;
};

and then

<VortexInvite
          widgetId={widgetID}
          isLoading={jwtLoading}
          jwt={jwt}
          emailValidationFunction={emailValidationFunction}
/>
If you return the optional errorMessage parameter it will be displayed in the widget UI to the user.

templateVariables

Template variables allow you to pass in information to be displayed in your invitation emails. For example, you might want to refer to the name of the inviter, the name of a workspace, or even the current number of members already in the workspace. For every variable added to your templates, you’ll need to pass in the values on this parameter.
templateVariables={{ inviter_name:"John Doe", workspace_name: "Acme", member_count: "26" }}

googleAppClientId

If your invitation flow includes the Google contact import, then you’ll need to pass in the Client ID for your Google app. See instructions for creating your app.

googleAppApiKey

If your invitation flow includes the Google contact import, then you’ll need to pass in the API key for your Google app. See instructions for creating your app.

onInvite

When passing an onInvite function, you are able to capture the invitations created by your users in the invitation widget. For example, if your service treats invitees as pending members for the purposes of email notifications and other functionality, you would want to know the email addresses and custom-field values for the invitees so that you could add them to your users table. If your service doesn’t care at all about invitees until they’ve accepted an invitation, then you don’t need to worry about this. This data format varies based on your widget configuration.
import type { OnInviteData } from '@teamvortexsoftware/vortex-react';

const onInvite = (invitations: Invitation[]) => {
	console.log("Invitations:", data);
	processData(data);
}

<VortexInvite
          widgetId={widgetID}
          isLoading={jwtLoading}
          jwt={jwt}
          onInvite={onInvite}
/>
Here is an example of the data passed to your registered onInvite function:
[{
acceptedAt: null,
​​	accountId: "43310069-8b56-4294-a0a6-79d910404d39",
​​	attributes: null,
​​	clickThroughs: 0,
​​	configurationAttributes: {
​​​		emails: {
​​​​			role: "email",
​​​​			type: "email",
​​​​			value: "foobar@barfoo.com"
		}
	},
​​	createdAt: "2025-08-25T18:55:50.551Z",
​​	deactivated: false,
​​	deliveryCount: 0,
​​	deliveryTypes: [
​​​		"email"
	],
	deploymentId: "8a95daf5-76ec-438c-ae34-b91b61d98f21",
​​	environmentId: "df3d007d-2716-41fc-ad32-5477230847b1",
​​	firstClickThrough: null,
​​	foreignCreatorId: "e6453ae2-6ca8-44f4-b0b5-b72f1f642e5e",
​​	id: "65b3c403-c03a-4baa-8eaa-20a40af31dd4",
​​	invitationType: "single_use",
​​	lastClickThrough: null,
​​	modifiedAt: null,
​​	passThrough: null,
​​	projectId: "35957e27-fdcd-482f-8462-2cbe9ab6ca77",
​​	senderIdentifier: "barfoo@foobar.com",
​​	senderIdentifierType: "email",
​​	source: "email",
​​	status: "queued",
​​	templateVariables: {
​​​	companyName: "AcmeTasks",
​​​		groupMemberCount: "1",
​	​​	groupName: "xxcbn",
​​​		inviterName: "yngwie User"
	},
​​	views: 0,
​​	widgetConfigurationId: "baf28550-8dcc-451e-9ec2-d17888a79fb6"
}, ...]

onEvent

When passing an onEvent function, you are able to capture events generated by your users via the invitation widget. For example, you might want to know when the user clicks on the “Invite” button in the invitation form you have during your onboarding process, so that you can advance the user to the next step in the onboarding flow as a result of that action. See the Vortex Events section for a complete list of events.
// see Vortex Events section for event type definitions
const AppEvent = widgetRender | widgetSubmit | widgetSubmitEmailFocus | widgetSubmitEmailBlur | widgetEmailValidation | widgetShareLinkClick | widgetSubmitValidationError | widgetSubmitError | widgetError;

const onEvent = (event: AppEvent) => {
	console.log("Event:", event);
	processEvent(event);
};

<VortexInvite
          widgetId={widgetID}
          isLoading={jwtLoading}
          jwt={jwt}
          onEvent={onEvent}
/>

isLoading

This prop is used to indicate that the invitation widget should not attempt to render yet, and instead render a loading placeholder. This can be used when all of the other props aren’t quite ready. For example:
export const vortexHarness = ({ parentIsLoading: boolean }) => {
const (jwt, jwtIsLoading) = useJwtHook();
const (isLoading, setIsLoading) = useState(parentIsLoading || jwtIsLoading);

useEffect(() => {
	setIsLoading(parentIsLoading || jwtIsLoading);
}, [parentIsLoading, jwtIsLoading]);

return (
<VortexInvite
          widgetId={widgetID}
          isLoading={isLoading}
          jwt={jwt}
          onSubmit={onSubmit}
/>
);
}