Mint your certificates as NFTs on Polygon Amoy — no server, no IPFS, pure on-chain.
CertifyNFT is a zero-backend static web app that lets you upload a certificate image, fill in metadata, and mint it as an ERC-721 NFT on Polygon Amoy testnet. The image and metadata are stored entirely on-chain as base64 data URIs — no API keys, no IPFS pinning services, no backend infrastructure.
Just static HTML, CSS and JavaScript served from GitHub Pages, talking directly to the blockchain through MetaMask and Ethers.js v6.
| Feature | Description |
|---|---|
| 🔗 MetaMask Integration | Auto-detect and connect MetaMask wallet |
| 🌐 Network Auto-Switch | Prompts to add/switch to Polygon Amoy (chain 80002) |
| 📷 Drag-and-Drop Upload | Supports PNG, JPG, and WebP images |
| 🖼️ Client-Side Compression | Canvas API resizes to ~50KB JPEG for cheap gas |
| 📝 Live Preview Card | Certificate preview updates as you type |
| 🔒 On-Chain Storage | Base64-encoded metadata, no IPFS dependency |
| 🎨 Premium Dark UI | Glassmorphism, neon purple/cyan gradients, animated BG |
| 📱 Mobile Responsive | Works on desktop and mobile browsers |
| 🔍 Gallery View | Shows NFTs owned by the connected wallet |
| 🔗 Explorer Links | Direct links to OpenSea Testnet & PolygonScan |
| Layer | Technology |
|---|---|
| Frontend | Pure HTML5, CSS3 (custom properties, glassmorphism), Vanilla JavaScript (ES6+) |
| Build | None — no bundler, no npm install, no framework |
| Blockchain SDK | Ethers.js v6 via CDN |
| Network | Polygon Amoy Testnet (chain ID 80002) |
| Smart Contract | Solidity ^0.8.20 + OpenZeppelin ERC721URIStorage |
| Hosting | GitHub Pages via GitHub Actions |
| Storage | On-chain base64 data URIs (no IPFS) |
| Wallet | MetaMask |
┌────────────────────────────────────────────────────────────┐
│ Browser (Client) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ index.html / styles.css │ │
│ │ Dark UI · Glassmorphism · Animations │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ app.js │ │
│ │ Wallet · Image Compression · Mint · Gallery │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────┐ ┌─────────────────┐ │
│ │ MetaMask │ │ Canvas API │ │
│ │ (window.eth) │ │ (compression) │ │
│ └────────┬───────┘ └─────────────────┘ │
└─────────────┼──────────────────────────────────────────────┘
│ Ethers.js v6 (CDN)
▼
┌────────────────────────────────────────────────────────────┐
│ Polygon Amoy Testnet (chain 80002) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ CertifyNFT.sol (ERC721URIStorage) │ │
│ │ │ │
│ │ mint(address to, string tokenURI) → tokenId │ │
│ │ tokenURI stores `data:application/json;base64,…` │ │
│ │ image embedded as `data:image/jpeg;base64,…` │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
certifynft/
├── index.html # Main single-page app
├── styles.css # Dark theme, glassmorphism, animations
├── app.js # Wallet, image compression, mint, gallery
├── config.js # Contract address & network config
├── contracts/
│ └── CertifyNFT.sol # ERC-721 smart contract
├── assets/
│ ├── favicon.svg
│ └── logo.svg
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Pages deployment
├── screenshot.png # README screenshot
├── PRD.md # Product requirements
├── README.md
└── LICENSE # MIT
- A modern browser (Chrome, Brave, Firefox, Edge)
- MetaMask wallet extension installed
- Free Polygon Amoy testnet MATIC — Alchemy Faucet
No build step required. Pick any of these:
# Clone the repo
git clone https://github.com/alfredang/certifynft.git
cd certifynft
# Option 1 — Open directly (file://)
open index.html
# Option 2 — Node local server (recommended)
npx serve .
# Option 3 — Python
python3 -m http.server 8000Then visit http://localhost:8000 (or whichever port your server prints).
ℹ️ Some browsers restrict certain APIs when opening via
file://. A local HTTP server is recommended.
- Connect Wallet — Click Connect Wallet and approve MetaMask.
- Switch Network — Approve the prompt to add/switch to Polygon Amoy.
- Get Test MATIC — Grab free testnet MATIC from the Alchemy Faucet.
- Upload Image — Drag-and-drop a PNG/JPG/WebP. It's auto-compressed to ~50KB.
- Fill Metadata — Title, recipient, issuer, description, and issue date.
- Mint NFT — Confirm in MetaMask and wait a few seconds.
- View Certificates — Your NFTs appear in the gallery with links to OpenSea & PolygonScan.
The app requires contracts/CertifyNFT.sol to be deployed on Polygon Amoy. Easiest path is Remix IDE (no install needed).
Step-by-step deployment via Remix
- Open Remix IDE.
- Create a new file
CertifyNFT.soland paste the contents ofcontracts/CertifyNFT.sol. - Open the Solidity Compiler tab → set compiler to
0.8.20→ Compile. - Open Deploy & Run Transactions → set Environment to Injected Provider — MetaMask.
- Ensure MetaMask is on Polygon Amoy. Select
CertifyNFT→ Deploy. - Confirm the transaction in MetaMask and wait for mining (a few seconds).
- Copy the deployed contract address from the Deployed Contracts panel.
After deployment, paste the address into config.js:
const CONFIG = {
CONTRACT_ADDRESS: '0xYOUR_CONTRACT_ADDRESS_HERE',
// ...
};Verify the contract on Amoy PolygonScan by pasting the address — you should see mint() and tokenURI() functions exposed.
Polygon Amoy MATIC is free from faucets. You'll need a tiny amount to pay gas.
| Faucet | URL |
|---|---|
| Alchemy (recommended) | https://www.alchemy.com/faucets/polygon-amoy |
| Official Polygon | https://faucet.polygon.technology/ |
Most faucets require a GitHub or Google login to prevent abuse.
This repo auto-deploys to GitHub Pages on every push to main via .github/workflows/deploy.yml.
To enable on a fork:
- Go to Settings → Pages.
- Under Build and deployment → Source, select GitHub Actions.
- Push to
main— the workflow handles the rest.
Your site will be live at https://<your-username>.github.io/certifynft/.
"Contract not deployed" error when minting
Update config.js with your deployed contract address. See Update config.js.
MetaMask keeps asking to switch network
Ensure MetaMask is set to Polygon Amoy (chain ID 80002). If you're already on Amoy, try disconnecting and reconnecting your wallet.
Image won't upload
Supported formats: PNG, JPG, WebP. Max raw size: 20MB. Try a smaller image.
Transaction failed — insufficient funds
You need MATIC on Polygon Amoy. Get free MATIC from the faucet.
Gallery shows nothing
The gallery only shows NFTs owned by the connected wallet. Make sure you've minted at least one certificate.
Contributions are welcome! To contribute:
- Fork the repo
- Create a feature branch (
git checkout -b feat/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feat/amazing-feature) - Open a Pull Request
For questions or ideas, open a GitHub Discussion or Issue.
MIT License — see LICENSE.
Tertiary Infotech Academy Pte. Ltd.
- Ethers.js — Ethereum library
- OpenZeppelin — audited ERC-721 contracts
- Polygon — Amoy testnet & ecosystem
- MetaMask — wallet provider
- Alchemy — Polygon Amoy faucet
- Remix IDE — zero-setup Solidity deployment
⭐ If this project helped you, give it a star on GitHub! ⭐
