· Nacho Coll · Guides · 10 min de lectura
Almacenamiento de metadatos NFT: la guía completa de IPFS para creadores de NFT
Guía paso a paso para almacenar metadatos NFT en IPFS. Incluye patrones tokenURI ERC-721 y ejemplos en Python y JavaScript.

Crear NFTs requiere más que simplemente desplegar un smart contract — necesitas un almacenamiento descentralizado y fiable para tus metadatos y activos. Esta guía completa te lleva paso a paso a través del almacenamiento de metadatos NFT en IPFS empleando las mejores prácticas del sector, con ejemplos de código para desarrolladores de Python y JavaScript.

¿Por qué IPFS para el almacenamiento de metadatos NFT?
El alojamiento web tradicional crea riesgos de centralización para los proyectos NFT. Cuando los metadatos residen en servidores convencionales, los NFT pueden quedar «rotos» si el servicio de hosting cae o cambia las URL. IPFS (InterPlanetary File System) resuelve esto proporcionando:
- Direccionamiento de contenido inmutable: Cada archivo obtiene un Content Identifier (CID) único que nunca cambia
- Almacenamiento descentralizado: El contenido existe en múltiples nodos por todo el mundo
- Verificación criptográfica: La integridad del archivo está garantizada mediante hashing de contenido
- URL a prueba de futuro: Los enlaces IPFS funcionan indefinidamente, protegiendo el valor a largo plazo
Para una comprensión más profunda de los fundamentos de IPFS, consulta nuestra guía sobre qué es IPFS pinning.
Entendiendo la estructura de metadatos ERC-721
El estándar ERC-721 define cómo deben estructurarse los metadatos NFT. La función tokenURI de tu smart contract devuelve una URL que apunta a metadatos JSON siguiendo este patrón:
{
"name": "My Amazing NFT #1",
"description": "A unique digital artwork showcasing...",
"image": "ipfs://QmYourImageCIDHere",
"attributes": [
{
"trait_type": "Background",
"value": "Blue"
},
{
"trait_type": "Rarity",
"value": "Common"
}
],
"external_url": "https://yourproject.com/token/1"
}Campos clave de metadatos
- name: El título del NFT mostrado en monederos y mercados
- description: Información detallada sobre el NFT
- image: URL de IPFS al activo visual principal
- attributes: Propiedades basadas en rasgos para filtrado y cálculos de rareza
- external_url: Enlace opcional a contenido adicional o al sitio web de tu proyecto
Proceso de almacenamiento de NFT en IPFS paso a paso
Paso 1: Prepara tus activos y metadatos
Antes de subir nada, organiza tus archivos:
- Activos principales: Imágenes, vídeos u otro contenido primario
- Archivos de metadatos: Archivos JSON que describen cada NFT
- Metadatos de colección: Información opcional a nivel de colección
Paso 2: Sube los activos a IPFS
Comienza subiendo tus activos NFT principales (imágenes, vídeos, etc.) para obtener sus IPFS CID. Harás referencia a estos CID en tus archivos JSON de metadatos.
Así puedes subir una imagen utilizando Python:
import requests
import base64
import json
def upload_image_to_ipfs(image_path, api_key):
"""Upload an image file to IPFS and return its CID"""
# Read and encode image
with open(image_path, 'rb') as f:
image_data = base64.b64encode(f.read()).decode('utf-8')
# Prepare upload payload
payload = {
"content": image_data,
"description": f"NFT Asset: {image_path}"
}
headers = {
"Content-Type": "application/json",
"X-Api-Key": api_key
}
# Upload to IPFS.NINJA
response = requests.post(
"https://api.ipfs.ninja/upload/new",
headers=headers,
json=payload
)
if response.status_code == 200:
result = response.json()
print(f"✅ Image uploaded successfully!")
print(f"CID: {result['cid']}")
print(f"IPFS URL: {result['uris']['ipfs']}")
print(f"Gateway URL: {result['uris']['url']}")
return result['cid']
else:
print(f"❌ Upload failed: {response.text}")
return None
# Example usage
API_KEY = "bws_1234567890abcdef1234567890abcdef" # Replace with your actual key
image_cid = upload_image_to_ipfs("my-nft-artwork.png", API_KEY)Paso 3: Crea y sube el JSON de metadatos
Una vez que tengas los CID de tus activos, crea archivos JSON de metadatos y súbelos:
def create_and_upload_metadata(name, description, image_cid, attributes, api_key):
"""Create NFT metadata JSON and upload to IPFS"""
# Create metadata object
metadata = {
"name": name,
"description": description,
"image": f"ipfs://{image_cid}",
"attributes": attributes
}
# Convert to JSON string and encode
metadata_json = json.dumps(metadata, indent=2)
metadata_b64 = base64.b64encode(metadata_json.encode('utf-8')).decode('utf-8')
# Upload metadata
payload = {
"content": metadata_b64,
"description": f"NFT Metadata: {name}",
"metadata": {
"contentType": "application/json",
"nftTokenId": name.split('#')[1] if '#' in name else "1"
}
}
headers = {
"Content-Type": "application/json",
"X-Api-Key": api_key
}
response = requests.post(
"https://api.ipfs.ninja/upload/new",
headers=headers,
json=payload
)
if response.status_code == 200:
result = response.json()
print(f"✅ Metadata uploaded successfully!")
print(f"Metadata CID: {result['cid']}")
return result['cid']
else:
print(f"❌ Metadata upload failed: {response.text}")
return None
# Example usage
attributes = [
{"trait_type": "Background", "value": "Cosmic Blue"},
{"trait_type": "Eyes", "value": "Laser"},
{"trait_type": "Rarity", "value": "Epic"}
]
metadata_cid = create_and_upload_metadata(
name="Cosmic Warrior #001",
description="A fierce warrior from the distant galaxies, wielding the power of stars.",
image_cid=image_cid,
attributes=attributes,
api_key=API_KEY
)Paso 4: Implementación en JavaScript
Para aplicaciones web o proyectos Node.js, aquí tienes el equivalente en JavaScript:
class NFTStorage {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.ipfs.ninja';
}
async uploadFile(fileContent, description) {
const payload = {
content: fileContent, // base64 encoded
description: description
};
const response = await fetch(`${this.baseUrl}/upload/new`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': this.apiKey
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`);
}
return await response.json();
}
async uploadImageFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async (e) => {
try {
const base64Content = e.target.result.split(',')[1]; // Remove data:image/...;base64, prefix
const result = await this.uploadFile(base64Content, `NFT Image: ${file.name}`);
resolve(result.cid);
} catch (error) {
reject(error);
}
};
reader.readAsDataURL(file);
});
}
async uploadMetadata(name, description, imageCid, attributes = []) {
const metadata = {
name,
description,
image: `ipfs://${imageCid}`,
attributes
};
const metadataJson = JSON.stringify(metadata, null, 2);
const base64Metadata = btoa(metadataJson);
const result = await this.uploadFile(base64Metadata, `NFT Metadata: ${name}`);
return result.cid;
}
}
// Usage example
const storage = new NFTStorage('bws_1234567890abcdef1234567890abcdef'); // Replace with your key
// Upload process
async function createNFT() {
try {
// Assuming you have a file input element
const fileInput = document.getElementById('nft-image');
const imageFile = fileInput.files[0];
console.log('Uploading image...');
const imageCid = await storage.uploadImageFromFile(imageFile);
console.log(`Image uploaded: ${imageCid}`);
console.log('Uploading metadata...');
const metadataCid = await storage.uploadMetadata(
'Galaxy Explorer #042',
'A mysterious explorer traversing the cosmic void.',
imageCid,
[
{ trait_type: 'Class', value: 'Explorer' },
{ trait_type: 'Galaxy', value: 'Andromeda' },
{ trait_type: 'Rarity', value: 'Legendary' }
]
);
console.log(`Metadata uploaded: ${metadataCid}`);
console.log(`Token URI: ipfs://${metadataCid}`);
} catch (error) {
console.error('Upload failed:', error);
}
}Implementación de tokenURI en tu Smart Contract
Una vez que tus metadatos estén subidos a IPFS, implementa la función tokenURI en tu contrato ERC-721:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFTCollection is ERC721, Ownable {
mapping(uint256 => string) private _tokenURIs;
string private _baseTokenURI;
constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
function setTokenURI(uint256 tokenId, string memory uri) external onlyOwner {
require(_exists(tokenId), "Token does not exist");
_tokenURIs[tokenId] = uri;
}
function setBaseURI(string memory baseURI) external onlyOwner {
_baseTokenURI = baseURI;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string) {
require(_exists(tokenId), "Token does not exist");
string memory _tokenURI = _tokenURIs[tokenId];
// Return specific token URI if set
if (bytes(_tokenURI).length > 0) {
return _tokenURI;
}
// Fall back to base URI + token ID pattern
if (bytes(_baseTokenURI).length > 0) {
return string(abi.encodePacked(_baseTokenURI, tokenId.toString()));
}
return "";
}
function mintWithURI(address to, uint256 tokenId, string memory uri) external onlyOwner {
_mint(to, tokenId);
_tokenURIs[tokenId] = uri;
}
}Operaciones por lotes para colecciones grandes
Para colecciones NFT grandes, las operaciones por lotes ahorran tiempo y costes de gas:
def batch_upload_collection(collection_data, api_key):
"""Upload an entire NFT collection in batches"""
print(f"Starting batch upload of {len(collection_data)} NFTs...")
results = []
for i, nft_data in enumerate(collection_data):
print(f"Processing NFT {i+1}/{len(collection_data)}: {nft_data['name']}")
try:
# Upload image
image_cid = upload_image_to_ipfs(nft_data['image_path'], api_key)
if image_cid:
# Upload metadata
metadata_cid = create_and_upload_metadata(
name=nft_data['name'],
description=nft_data['description'],
image_cid=image_cid,
attributes=nft_data['attributes'],
api_key=api_key
)
if metadata_cid:
results.append({
'token_id': i + 1,
'name': nft_data['name'],
'image_cid': image_cid,
'metadata_cid': metadata_cid,
'token_uri': f"ipfs://{metadata_cid}"
})
except Exception as e:
print(f"❌ Error processing {nft_data['name']}: {e}")
print(f"✅ Batch upload complete! {len(results)} NFTs processed successfully.")
return results
# Example collection data
collection_data = [
{
'name': 'Cosmic Warrior #001',
'description': 'A fierce warrior from distant galaxies.',
'image_path': 'images/warrior_001.png',
'attributes': [
{'trait_type': 'Class', 'value': 'Warrior'},
{'trait_type': 'Rarity', 'value': 'Epic'}
]
},
# Add more NFTs...
]
results = batch_upload_collection(collection_data, API_KEY)Buenas prácticas para el almacenamiento de metadatos NFT
1. Utiliza nombres de archivo descriptivos
Al subir a IPFS, usa descripciones significativas para ayudar con la organización:
payload = {
"content": base64_content,
"description": f"Collection: {collection_name} | Token: {token_id} | Type: {file_type}"
}2. Implementa una gestión de errores adecuada
Siempre maneja los fallos de subida con elegancia:
import time
def upload_with_retry(upload_function, max_retries=3, delay=2):
"""Upload with exponential backoff retry logic"""
for attempt in range(max_retries):
try:
return upload_function()
except Exception as e:
if attempt == max_retries - 1:
raise e
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay} seconds...")
time.sleep(delay)
delay *= 2 # Exponential backoff3. Valida la estructura de metadatos
Asegúrate de que tus metadatos cumplen con los estándares:
def validate_metadata(metadata):
"""Validate NFT metadata structure"""
required_fields = ['name', 'description', 'image']
for field in required_fields:
if field not in metadata:
raise ValueError(f"Missing required field: {field}")
if not metadata['image'].startswith('ipfs://'):
raise ValueError("Image must be an IPFS URL")
if 'attributes' in metadata:
for attr in metadata['attributes']:
if 'trait_type' not in attr or 'value' not in attr:
raise ValueError("Invalid attribute structure")
return TrueEligiendo el servicio de pinning IPFS adecuado
Al seleccionar un servicio de pinning IPFS para tu proyecto NFT, considera:
- Fiabilidad: Tiempo de actividad garantizado para almacenamiento a largo plazo
- Rendimiento: Velocidades de recuperación rápidas en todo el mundo
- Precio: Coste eficiente para el tamaño de tu colección
- Funciones: Capacidades de API, analítica y herramientas para desarrolladores
Para una comparación detallada de servicios de pinning, lee nuestra comparación IPFS Ninja vs Pinata y nuestra guía sobre los mejores servicios de pinning IPFS.
Funciones avanzadas: pasarelas personalizadas y analítica
IPFS Ninja ofrece funciones adicionales para proyectos NFT profesionales:
Configuración de pasarela personalizada
Crea pasarelas IPFS con marca para tu colección:
// Access your NFT through a custom gateway
const customGateway = 'https://my-collection.gw.ipfs.ninja';
const nftUrl = `${customGateway}/ipfs/${metadataCid}`;Analítica de subidas
Monitoriza el uso de almacenamiento NFT y los patrones de acceso mediante la analítica del panel de control, ayudándote a entender el rendimiento de la colección y optimizar los costes de almacenamiento.
Solución de problemas comunes
Los metadatos no se cargan
- Verifica que las URL IPFS usen el protocolo
ipfs:// - Comprueba que el JSON de metadatos sea válido
- Asegúrate de que el servicio de pinning mantiene el contenido
Las imágenes no se muestran
- Confirma que los CID de las imágenes son correctos en los metadatos
- Prueba las URL de las imágenes en las pasarelas IPFS
- Verifica que los formatos de archivo de imagen sean compatibles con la web
Errores de estimación de gas
- Asegúrate de que la función
tokenURIdevuelve cadenas válidas - Comprueba referencias circulares en los metadatos
- Valida todos los CID IPFS antes del minting
Monitoreo y mantenimiento de tu almacenamiento NFT
Después de desplegar tu colección:
- Comprobaciones de salud regulares: Verifica que los metadatos y las imágenes siguen siendo accesibles
- Respalda los CID importantes: Mantén registros de todos los identificadores de contenido subidos
- Monitoriza la analítica: Realiza un seguimiento de los patrones de acceso y el uso del almacenamiento
- Planifica el escalado: Considera actualizar tu servicio de pinning a medida que crece tu colección
Para más detalles sobre la gestión programática de subidas, consulta nuestro tutorial de la API de subida IPFS.
Conclusión
Almacenar metadatos NFT en IPFS asegura que tus activos digitales permanezcan accesibles y valiosos a largo plazo. Siguiendo esta guía, has aprendido a:
- Estructurar metadatos compatibles con ERC-721
- Subir activos y metadatos utilizando Python y JavaScript
- Implementar funciones
tokenURIadecuadas - Gestionar operaciones por lotes para colecciones grandes
- Aplicar buenas prácticas para despliegues en producción
La combinación de la arquitectura descentralizada de IPFS y los servicios de pinning fiables crea la base para proyectos NFT exitosos que resisten el paso del tiempo.
¿Listo para empezar con el pinning? Crea una cuenta gratuita — 50 archivos, 1 GB de almacenamiento, 2 GB de ancho de banda/mes. No se requiere tarjeta de crédito.
