Cover photo

Effortlessly Enhance Your dApp with Jupiter Terminal in Just a Few Lines of Code

Want to seamlessly integrate end-to-end swap functionality into your dApp with minimal effort? You’re in the right place! This guide walks you through key considerations, technical nuances, and a step-by-step approach to embedding Jupiter Terminal in your HTML.


In my previous article, I broke down how Jupiter Swap works and demonstrated how you can 10x your dApp development speed when creating React hooks powered by Jupiter’s APIs for seamless swap integration.

But what if I told you that you could 100x your speed and build a dApp with full swap functionality in record time?

That is exactly what we are exploring today. Introducing Jupiter Terminal, an open-source, lightweight version of Jupiter that seamlessly embeds into your HTML. Imagine your dApp having a swap component that looks and feels just like jup.ag. That is the added power that Jupiter Terminal brings with no unnecessary redirects, no disruptions, just a flawless user experience.

In this Builder Guide, I'll be going through how you can integrate Jupiter Terminal directly into your HTML, while also detailing how you can customize the configurations of the swap terminal, allowing you to choose the display mode that best suit your needs. Additionally, I'll also navigate you through some of the JavaScript technical nuances so that you can successfully build from scratch your own swap Terminal.

So, what exactly is Jupiter Terminal?

Well, think of it as a lightweight, plug-and-play version of what you see on jup.ag. It's core purposes? Delivering a seamless, end-to-end swap flow that you can integrate effortlessly with only just a few lines of code in your HTML.

As of today (03/01/2025) in terms of Space Station's documentation, Jupiter's APIs currently only consists of the Swap V6 API endpoint (which will be deprecated soon) and also the newly improved Swap V1 API endpoint that only contains Manual Mode.

Meanwhile, Jupiter Terminal is already ahead of the curve, fully equipped with Ultra Mode and its cutting-edge innovations, such as:

Real-time slippage estimation (RTSE) Leverages real-time swap data from actual users, historical trends, and heuristics to determine the most optimal slippage for each trade, minimizing losses and improving execution efficiency.

Dynamic priority fees Estimates optimal transaction fees by analyzing network activity, swap size, and interactions with high-traffic accounts, ensuring your transactions are prioritized without unnecessary overpayment.

Optimised transaction landing Fires transactions across multiple providers simultaneously, increasing the likelihood of successful execution, especially in volatile market conditions.

Jupiter Shield (coming soon) Designed to enhance security and safeguard swaps from potential risks in token selection.

Step-By-Step Guide: Integrating and Configuring Jupiter Terminal in your HTML

To lay the basis, I will be exploring two approaches of how you can integrate Jupiter Terminal into a Typescript React application, both of which begin by embedding a <script> tag in a HTML file.  The first method involves initializing the Jupiter object via window object, while the second method leverages the @jup-ag/terminal npm package to initialize Jupiter Terminal.

Declaring Typescript Support (ONLY FOR Typescript React Apps)

As we are building in a Typescript React application for this Builder Guide, we will need to do this step. Since Jupiter Terminal is only importable via CDN, to get proper typing, you will need to create a type declaration file - terminal.d.ts - in your project's types folder and copy the following content.

declare global { interface Window { Jupiter: JupiterTerminal; } }

Embedding a <script> tag in your HTML file

In today’s development landscape, there are many different React-based frameworks that are widely used for building applications. For this builder guide, we will demonstrate two approaches: one for a plain React application and another specifically for Next.js projects.

React Application Example

In your index.html file, include the following code to allow Terminal to work anywhere in your web application.

<head> ... <script src='https://terminal.jup.ag/main-v4.js' data-preload defer></script> </head>

Next.js Application Example

For Next.js applications, you can modify your app.tsx or _app.js file with the Next.js built-in next/script component.

import Script from 'next/script'; function MyApp({ Component, pageProps }) { return ( <> <Script src="https://terminal.jup.ag/main-v4.js" strategy="beforeInteractive" // this allows it to load early like a <head> script data-preload // custom attribute defer // ensures that it does not block parsing /> <Component {...pageProps} /> </> ); } export default MyApp;

If your Next.js application follows the App Router structure rather than the older Pages Router, you can place the script in the layout.tsx to apply it globally across your application.

import Script from 'next/script'; import type { Metadata } from 'next'; import './globals.css'; export const metadata: Metadata = { title: 'Jupiter Terminal Example', description: 'Effortlessly Integrate Jupiter Terminal into your dApp', }; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <Script src="https://terminal.jup.ag/main-v4.js" strategy="beforeInteractive" data-preload defer /> </head> <body> {children} </body> </html> ); }

Now that the Terminal script is embedded in your React application, it’s ready to be used throughout your project. But how do we initialize it?

Method 1 - Initializing a Jupiter object via window object

React Application Example

If you are using a plain React application that contains index.html, you can simply initialize a Jupiter via the window object in your <body>.

<body> <h1>Jupiter Swap Demo</h1> <div id="jupiter-terminal"></div> <script> document.addEventListener("DOMContentLoaded", function () { const jupiterTerminal = document.createElement('div') // create jupiter terminal div jupiterTerminal.id = 'jupiter-terminal' document.body.appendChild(jupiterTerminal) // initialize jupiter terminal window.Jupiter.init({ displayMode: "integrated", integratedTargetId: "integrated-terminal", endpoint: "https://mainnet.helius-rpc.com/?api-key=HELIUS_API_KEY", formProps: { fixedOutputMint: false } }); }); </script> </body>

Next.js Application Example

For Next.js applications, you can initialize Jupiter Terminal via a useEffect hook and adding a <div> with the id of the terminal that has been declared.

"use client"; import React, { useEffect } from "react"; export default function TerminalExample() { useEffect(() => { if (typeof window !== "undefined") { window.Jupiter.init({ displayMode: "integrated", integratedTargetId: "integrated-terminal", endpoint: "https://mainnet.helius-rpc.com/?api-key=HELIUS_API_KEY", }); } }, []); return ( <div> <h1>Jupiter Terminal Example</h1> {/* This is where the terminal will be embedded */} <div id="integrated-terminal" style={{ width: "100%", height: "500px" }}></div> </div> ); }

Method 2 - Initializing Terminal using @jup-ag/terminal

Alternatively, you can also initialize Jupiter Terminal via the npm package @jup-ag/terminal.

Prerequisites

After installing this package, you can use a useEffect hook and initialize Terminal like this.

"use client"; import React, { useEffect } from "react"; import "@jup-ag/terminal/css"; export default function TerminalExample() { useEffect(() => { if (typeof window !== "undefined") { import("@jup-ag/terminal").then((mod) => { const { init } = mod; init({ displayMode: "integrated", integratedTargetId: "integrated-terminal", endpoint: "https://api.mainnet-beta.solana.com", }); }); } }, []); return ( <div> <h1>Jupiter Terminal</h1> {/* This is where the terminal will be embedded */} <div id="integrated-terminal" style={{ width: "100%", height: "500px" }}></div> </div> ); }

Jupiter Terminal's Display Modes

From the code above, I have demonstrated Jupiter Terminal using only the Integrated display mode. However, Jupiter Terminal is highly versatile and supports a total of three display modes to suit different use cases: Integrated, Widget, and Modal.

For each display mode, I will outline the customizable parameters that allow you to modify the Terminal’s behavior based on your chosen mode.

Integrated Terminal

interface IntegratedTerminal { displayMode: "integrated"; integratedTargetId: string; /** Form configuration options */ formProps: { /** Initial amount to swap */ initialAmount?: string; /** When true, user cannot change the amount (e.g. for Payments) */ fixedAmount?: boolean; /** Initial input token to swap */ initialInputMint?: string; /** When true, user cannot change the input token */ fixedInputMint?: boolean; /** Initial output token to swap */ initialOutputMint?: string; /** When true, user cannot change the output token (e.g. to buy your project's token) */ fixedOutputMint?: boolean; }; /** Restrict token selection to a predefined list */ strictTokenList: boolean; /** Style using CSS properties */ containerStyles: React.CSSProperties; /** Style using Tailwind CSS class names */ containerClassName: string; /** Triggered when an error occurs during the swap process */ onSwapError?: ({ error, quoteResponseMeta, }: { error?: TransactionError; quoteResponseMeta: QuoteResponse | null; }) => void; /** Triggered when a swap transaction is successfully completed */ onSuccess?: ({ txid, swapResult, quoteResponseMeta, }: { txid: string; swapResult: SwapResult; quoteResponseMeta: QuoteResponse | null; }) => void; }

Widget Terminal

type WidgetPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right"; type WidgetSize = "sm" | "default"; interface WidgetTerminal { displayMode: "widget"; /** Form configuration options */ formProps: { /** Initial amount to swap */ initialAmount?: string; /** When true, user cannot change the amount (e.g. for Payments) */ fixedAmount?: boolean; /** Initial input token to swap */ initialInputMint?: string; /** When true, user cannot change the input token */ fixedInputMint?: boolean; /** Initial output token to swap */ initialOutputMint?: string; /** When true, user cannot change the output token (e.g. to buy your project's token) */ fixedOutputMint?: boolean; }; /** Restrict token selection to a predefined list */ strictTokenList: boolean; /** When displayMode is 'widget', this is the behaviour and style of the widget */ widgetStyle?: { position?: WidgetPosition; size?: WidgetSize; }; /** Triggered when an error occurs during the swap process */ onSwapError?: ({ error, quoteResponseMeta, }: { error?: TransactionError; quoteResponseMeta: QuoteResponse | null; }) => void; /** Triggered when a swap transaction is successfully completed */ onSuccess?: ({ txid, swapResult, quoteResponseMeta, }: { txid: string; swapResult: SwapResult; quoteResponseMeta: QuoteResponse | null; }) => void; }

Modal Terminal

interface ModalTerminal { displayMode: "modal"; /** Form configuration options */ formProps: { /** Initial amount to swap */ initialAmount?: string; /** When true, user cannot change the amount (e.g. for Payments) */ fixedAmount?: boolean; /** Initial input token to swap */ initialInputMint?: string; /** When true, user cannot change the input token */ fixedInputMint?: boolean; /** Initial output token to swap */ initialOutputMint?: string; /** When true, user cannot change the output token (e.g. to buy your project's token) */ fixedOutputMint?: boolean; }; /** Restrict token selection to a predefined list */ strictTokenList: boolean; /** Triggered when an error occurs during the swap process */ onSwapError?: ({ error, quoteResponseMeta, }: { error?: TransactionError; quoteResponseMeta: QuoteResponse | null; }) => void; /** Triggered when a swap transaction is successfully completed */ onSuccess?: ({ txid, swapResult, quoteResponseMeta, }: { txid: string; swapResult: SwapResult; quoteResponseMeta: QuoteResponse | null; }) => void; }

For Modal Terminal, you can create a <button> with an onClick handler function that calls a function that initializes the Jupiter Terminal.

import React from 'react'; export default function ModalTerminalExample() { const handleLaunchTerminal = () => { window.Jupiter.init({ displayMode: "modal", integratedTargetId: "modal-terminal", endpoint: "https://mainnet.helius-rpc.com/?api-key=HELIUS_API_KEY", }); }; return ( <button onClick={handleLaunchTerminal}> <span>Launch Terminal Modal</span> </button> ); }

Summing this step-by-step guide, we explored two approaches to integrating Jupiter Terminal into a TypeScript React application. Both methods involved embedding the Jupiter Terminal script in the application, with initialization handled either through the window object or via the @jup-ag/terminal package using the useEffect hook.

For React applications, we demonstrated how to include the script in index.html and initialize Jupiter Terminal within the <body>. For Next.js applications, we leveraged Next.js built-in next/script component and integrated the terminal either in _app.js, layout.tsx, or inside a specific page component using useEffect.

With Jupiter Terminal now set up in your application, you can take advantage of its three display modesIntegrated, Widget, and Modal—to best suit your needs.

Conclusion

Jupiter Terminal revolutionizes swap integration by providing a lightweight, open-source solution that seamlessly embeds into your dApp with minimal effort. Whether you want a fully embedded experience, a floating widget, or a sleek modal, Jupiter Terminal adapts to your design needs while maintaining quality end-to-end swaps without unnecessary redirects or disruptions.

I hope that this guide has provided you with a clear and practical understanding of how to integrate Jupiter Terminal into your dApp, enabling you to streamline swap functionality with minimal effort. Whether you’re building with React or any React-based frameworks, leveraging window-based initialization or the @jup-ag/terminal package, you now have the tools to create a seamless and efficient swap experience for your users.

As Jupiter Terminal continues to evolve, integrating it into your dApp ensures that you’re always at the forefront of Solana DeFi innovation.

Welcome to the Jupiverse

Loading...
highlight
Collect this post to permanently own it.
Buidling Onchain logo
Subscribe to Buidling Onchain and never miss a post.
#solana#defi#swap#jupiter#terminal#react#nextjs#typescript#html