Before You Start — Understanding The Grid
What Is The Grid?
Every Universal Profile on LUKSO has a section called The Grid. Think of it like the home screen on your phone — you can add widgets like a weather app, a clock, or a photo slideshow. The Grid works the same way, but for your blockchain identity.
The Grid is a customizable area on your Universal Profile page where you can embed mini apps — small interactive websites that live right on your profile. Anyone who visits can see and interact with them.
What Is a Mini App?
A mini app is just a website — a small one, designed to fit in a card-sized space on your Grid. Here's the good news: you don't need to know how websites work. An AI tool will build the entire thing for you based on what you tell it in plain English.
What You'll End Up With
The whole journey: Build it → Publish it → Add it to your profile.
What Accounts Do You Need?
Time estimate
45–60 minutes if things go smoothly. Up to 90 if this is your first time with tools like these. Don't rush it.
One important rule: HTTPS only
Your mini app's URL must start with https:// (not http://). The Grid requires it for security. Vercel gives you HTTPS automatically.
Before You Continue, You'll Need:
Note: If your app uses the LUKSO Relayer API, users can transact without needing LYX for gas. Adding your mini app to the Grid still requires a small gas fee from your own account.
Building Your Mini App with AI
Why Bolt.new?
Official LUKSO mini app template available
The LUKSO team maintains an official Next.js mini app template with up-provider, erc725.js, and web-components pre-configured.
View on GitHub →Cursor tip: rename the template README.md to .cursorrules for better AI assistance in Cursor.
Other options like Lovable, v0, or Replit work too — Bolt.new is recommended for its zero-install browser experience and instant preview.
Getting Started
The Starter Prompt
Copy the entire block below and paste it into Bolt.new. Don't change anything — just paste and hit Enter.
Build me a single-page web app that works as a LUKSO Universal Profile mini app with wallet connection. Here are the exact requirements:
WHAT IT DOES:
- Shows a "Connect your Universal Profile" button on first load
- When clicked, it connects using the official UP Provider package
- After connecting, it reads and displays the connected user's profile: name, bio/description, and profile picture
- Also shows the connected wallet address (shortened: first 6 + last 4 chars)
- Shows follower count via the Envio indexer
- Shows a "Disconnect" button after connecting
SETUP — Install these official LUKSO packages via npm:
- @lukso/up-provider: for UP wallet connection on the Grid (EIP-1193 compatible provider)
- @erc725/erc725.js: for fetching ERC725Y profile data (decodes VerifiableURI, resolves IPFS automatically)
- @lukso/lsp-utils: for high-level helpers like getProfileMetadata()
- @lukso/web-components: for pre-built branded profile UI components (e.g. <lukso-profile-preview>)
- ethers: for blockchain interaction
Reference template: https://github.com/lukso-network/miniapp-nextjs-template
HOW TO CONNECT (using @lukso/up-provider — NOT raw window.lukso):
import { createClientUPProvider } from '@lukso/up-provider';
const provider = createClientUPProvider();
// provider is EIP-1193 compatible — works with ethers.js BrowserProvider
// To get accounts:
const accounts = await provider.request({ method: 'eth_requestAccounts' });
// accounts[0] is the connected Universal Profile address
// If provider is not available, show: "Please open this in the LUKSO Grid or install the UP Extension"
// Do NOT use window.lukso or window.ethereum directly — always use createClientUPProvider()
Reference: https://docs.lukso.tech/learn/dapp-developer/getting-started
Reference: https://www.npmjs.com/package/@lukso/up-provider
HOW TO FETCH PROFILE DATA (using @erc725/erc725.js + @lukso/lsp-utils — NOT manual ABI calls):
import { getProfileMetadata } from '@lukso/lsp-utils';
// getProfileMetadata(address, provider) returns { name, description, profileImage, backgroundImage, tags }
// It handles all ERC725Y decoding, VerifiableURI parsing, and IPFS resolution internally
// IPFS gateway: https://api.universalprofile.cloud/ipfs/
// Alternative: use ERC725.js directly for more control:
import ERC725 from '@erc725/erc725.js';
import lsp3ProfileSchema from '@erc725/erc725.js/schemas/LSP3ProfileMetadata.json';
const erc725 = new ERC725(lsp3ProfileSchema, address, 'https://rpc.mainnet.lukso.network', {
ipfsGateway: 'https://api.universalprofile.cloud/ipfs/',
});
const profileData = await erc725.fetchData('LSP3Profile');
// profileData.value.LSP3Profile contains { name, description, profileImage, backgroundImage, tags }
// Do NOT manually call getData(bytes32[]) or decode VerifiableURI by hand — the libraries handle this.
Reference: https://docs.lukso.tech/standards/metadata-detection
Reference: https://www.npmjs.com/package/@erc725/erc725.js
Reference: https://www.npmjs.com/package/@lukso/lsp-utils
PROFILE UI (using @lukso/web-components):
import '@lukso/web-components';
// Use <lukso-profile-preview address="0x..." /> for an instant branded profile card
// The component handles fetching and rendering profile data automatically
// You can also build a custom card using the data from getProfileMetadata()
Reference: https://www.npmjs.com/package/@lukso/web-components
ALSO FETCH FOLLOWER COUNT (via Envio indexer):
// Note: The Envio indexer is currently free but may become a paid service in the future.
fetch('https://envio.lukso-mainnet.universal.tech/v1/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `query { followerCount: Follow_aggregate(where: {followee: {_eq: "${address}"}}) { aggregate { count } } }` })
})
Reference: https://github.com/lukso-network/tools-lsp-utils
DESIGN:
- LUKSO brand colors: magenta #FE005B as accent color, dark background (#0a0a0a), white text
- Clean, modern card layout centered on the page
- Profile picture in a large circle (120px) with a subtle magenta ring
- Name in large bold font, description in smaller muted text
- Address displayed in a monospace code style with subtle background
- "Connect" button: magenta #FE005B background, white text, rounded-full, with wallet icon
- Mobile responsive
- Must work when embedded in an iframe (LUKSO Grid context)
UX DETAILS:
- Before connecting: centered connect button with LUKSO logo/icon and tagline "Connect your Universal Profile"
- After connecting: profile card slides in with avatar, name, bio, address, follower count
- Loading state: subtle pulsing skeleton while fetching profile data
- Error state: friendly message if connection fails or profile not found
Wait and Watch
Customize It
Keep chatting with Bolt.new to change anything. Each message updates the code and preview instantly.
If you see a profile name, description, and picture — congratulations. You just built a blockchain app without writing a single line of code.
💡 Not sure what to build?
Browse 12 community mini app ideas — from a tip jar to an NFT gallery to a live follower counter.
Publishing Your App Online
Your app looks great in Bolt.new's preview — but that preview is temporary. To add it to your Grid, you need a permanent public URL. That's what "deploying" means: putting your app on the internet for real.
https://your-app-name.vercel.app or similar✓ If this worked, skip to "Test Your URL" below.
https://your-project.vercel.appTest Your URL Before Moving On
Save your URL. Email it to yourself or put it in your notes. You'll need it in the next step.
Adding Your App to Your Universal Profile Grid
What You Need
Adding Your App via universaleverything.io
What does the transaction actually do?
When you add a mini app to your Grid, you're saving that URL directly to your Universal Profile's on-chain data. That's why the extension asks you to approve — you're writing data to the blockchain. This costs a tiny amount of LYX (gas fee).
Verify It Worked
Anyone who visits your profile now sees your mini app. You just added a custom, interactive widget to your on-chain identity. 🎉
Troubleshooting, Pitfalls & Next Steps
The 11 Most Common Beginner Mistakes
Save Your Work (Do This Now)
What Comes Next
- Static profile showcase — what this guide built
- Token balance display (LSP7)
- Live LYX price widget
- Mini social feed from Forever Moments
- Gasless transactions via Relayer API (no LYX needed for users)
- @lukso/web-components profile cards
- Interactive tip jar (send LYX button)
- Custom smart contract frontend
- LSP7/LSP8 token interfaces
- Smart contract development with lsp-smart-contracts
- Foundry template for Solidity contracts
Mini Glossary
| URL | A web address — the text in your browser's address bar (like https://example.com). |
| Deploy | Uploading your app to a hosting service so anyone on the internet can visit it. |
| Repository (Repo) | A folder on GitHub that stores your project's code. |
| Frontend | What users see in their browser (HTML, CSS, JavaScript) — this guide only needs frontend. |
| iframe | A window inside a webpage that displays another webpage — how the Grid shows your mini app. |
| Transaction | A signed action on the blockchain that costs a small fee (gas). |
| LYX | LUKSO's native currency — needed in small amounts for transaction fees. |
| ERC725Y | The storage system for your Universal Profile — a database attached to your profile. |
| LSP28 | The standard that defines how the Grid works on Universal Profiles. |
| RPC Endpoint | The address your app uses to talk to the LUKSO blockchain. |
Where to Get Help
Your First Real Build: A Profile Viewer
You've learned the full pipeline: build → deploy → add to Grid. Now let's build something that actually reads live data from LUKSO. This mini app lets anyone enter a Universal Profile address (or username) and see their name, bio, avatar, and follower count — all fetched directly from the blockchain and IPFS.
What You'll Learn
How the Profile Viewer Works
Build me a single-page web app that works as a LUKSO Universal Profile Viewer. Here are the exact requirements:
WHAT IT DOES:
- Shows an input field where users can enter a Universal Profile address (0x...) or a UP username
- Has a "View Profile" button that fetches and displays the profile
- Displays: profile name, bio/description, profile picture (avatar), and follower count
- Also shows the full address in a monospace code style
- Optional wallet connection button for Grid context
SETUP — Install these official LUKSO packages via npm:
- @lukso/up-provider: for UP wallet connection on the Grid (EIP-1193 compatible provider)
- @erc725/erc725.js: for fetching ERC725Y profile data (decodes VerifiableURI, resolves IPFS automatically)
- @lukso/lsp-utils: for high-level helpers like getProfileMetadata()
- @lukso/web-components: for pre-built branded profile UI components (e.g. <lukso-profile-preview>)
- ethers: for blockchain interaction
Reference template: https://github.com/lukso-network/miniapp-nextjs-template
HOW TO RESOLVE USERNAMES:
If the input doesn't start with "0x", treat it as a username and resolve it via Envio GraphQL:
// Note: The Envio indexer is currently free but may become a paid service in the future.
fetch('https://envio.lukso-mainnet.universal.tech/v1/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `query { Profile(where: {name: {_eq: "${username}"}}) { id name } }` })
})
The "id" field in the response is the profile address.
HOW TO FETCH PROFILE DATA (using @erc725/erc725.js + @lukso/lsp-utils — NOT manual ABI calls):
import { getProfileMetadata } from '@lukso/lsp-utils';
// getProfileMetadata(address, provider) returns { name, description, profileImage, backgroundImage, tags }
// It handles all ERC725Y decoding, VerifiableURI parsing, and IPFS resolution internally
// IPFS gateway: https://api.universalprofile.cloud/ipfs/
// Alternative: use ERC725.js directly for more control:
import ERC725 from '@erc725/erc725.js';
import lsp3ProfileSchema from '@erc725/erc725.js/schemas/LSP3ProfileMetadata.json';
const erc725 = new ERC725(lsp3ProfileSchema, address, 'https://rpc.mainnet.lukso.network', {
ipfsGateway: 'https://api.universalprofile.cloud/ipfs/',
});
const profileData = await erc725.fetchData('LSP3Profile');
// profileData.value.LSP3Profile contains { name, description, profileImage, backgroundImage, tags }
// Do NOT manually call getData(bytes32[]) or decode VerifiableURI by hand — the libraries handle this.
PROFILE UI (using @lukso/web-components):
import '@lukso/web-components';
// Use <lukso-profile-preview address="0x..." /> for an instant branded profile card
// The component handles fetching and rendering profile data automatically
// You can also build a custom card using the data from getProfileMetadata()
HOW TO FETCH FOLLOWER COUNT:
// Note: The Envio indexer is currently free but may become a paid service in the future.
fetch('https://envio.lukso-mainnet.universal.tech/v1/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `query { followerCount: Follow_aggregate(where: {followee: {_eq: "${address}"}}) { aggregate { count } } }` })
})
OPTIONAL — WALLET CONNECTION (using @lukso/up-provider — NOT raw window.lukso):
import { createClientUPProvider } from '@lukso/up-provider';
const provider = createClientUPProvider();
// provider is EIP-1193 compatible
const accounts = await provider.request({ method: 'eth_requestAccounts' });
// When connected, auto-fill the input with accounts[0] and load their profile
// This makes it work as a Grid mini app too
// Do NOT use window.lukso or window.ethereum directly — always use createClientUPProvider()
DESIGN:
- LUKSO brand colors: magenta #FE005B as accent, dark background (#0a0a0a), white text
- Clean search bar at the top with the input and button side by side
- Profile card below: avatar in a large circle (120px) with magenta ring, name bold, bio muted, address monospace
- Follower count shown with a small people icon
- Mobile responsive, works in iframe (Grid context)
- Loading: pulsing skeleton placeholders
- Error: friendly message if profile not found
Try It Live — Find a Profile Address
Need a Universal Profile address to test with? Browse real profiles on Universal Everything to find one. Click on any profile, copy their address from the URL bar, and paste it into your Profile Viewer.
Browse Universal ProfilesPro Tips for This Build
- •If you get CORS errors, switch the RPC to
https://42.rpc.thirdweb.com - •The IPFS gateway
api.universalprofile.cloud/ipfs/{CID}is the most reliable for LUKSO profile data - •Use
@lukso/up-providerfor wallet connection so it works as a Grid mini app - •Once it works, deploy to Vercel and add it to your Grid — you've now built a real LUKSO dApp
