Back to blog
How to Implement Progress Indicators and Resumable Uploads with Pinata
We’ve all lost hours of progress on a large file upload because of an untimely internet glitch — and we all hate it.
Developers want to do everything in their power to stop that from happening, but factors such as connection interruptions, long upload times, and bandwidth limitations are often beyond their control. To mitigate these blows to user experience, developers use progress indicators and resumable uploads.
In this article, we offer a step-by-step guide for implementing both of these features with Pinata, plus some example code.
What are the benefits of resumable uploads and progress indicators?
Resumable uploads and progress indicators add a lot of value to web and mobile apps:
- Reliability: These features save progress, time, and bandwidth by optimizing the upload process and reducing downtime and errors.
- Transparency: Users stay informed about the upload’s progress, which reduces uncertainty and increases engagement. As a result, fewer users abandon the upload (and your app).
- Efficiency: Only incomplete chunks need to be re-uploaded, which streamlines the process and reduces user frustration.
- User satisfaction: By eliminating the frustration of starting over after an interruption, you build trust in your system and boost user confidence.
Resumable uploads
Resumable uploads allow files to be uploaded in chunks, enabling the process to resume from the point of interruption rather than restarting entirely. This capability helps in handling large file transfers, where interruptions are more likely due to extended upload times or network instability, such as intermittent Wi-Fi or mobile data dropouts or sudden power outages. It’s also handy for server timeouts due to lengthy uploads or user-triggered interruptions like accidentally closing the browser or switching tasks mid-upload.
Progress indicators
Progress indicators work hand in hand with resumable uploads, playing a vital role in improving the upload experience for large file uploads, especially when creators rely on progress indicators to manage their time effectively. By showing users how much of the process is complete and how much remains, users get real-time feedback on the status of their uploads. In cloud backup services, users uploading extensive datasets depend on these indicators to ensure their backups are proceeding as expected. Similarly, e-commerce platforms benefit from progress visibility, as sellers efficiently upload entire product catalogs, especially during bulk uploads.
How to set up progress indicators and resumable uploads in 4 easy steps using Pinata
Implementing progress indicators and resumable uploads with Pinata is straightforward and can be completed in just four steps.
1. Set up Pinata
To begin, integrate Pinata into your project with our powerful SDK or API. This will allow swift interaction with Pinata's file upload services.
- Pinata SDK/API: The SDK simplifies uploading files and managing metadata, while the API provides more control for custom integrations. You can access the Pinata SDK via npm or use the Pinata API documentation for direct API integrations.
- Authentication with Pinata JWT: Secure your uploads by including the Pinata JWT in your requests. Generate a JWT token from your Pinata dashboard under the API Keys section, and include it in the Authorization header of your requests.
2. Implement resumable uploads
Resumable uploads are made possible through Pinata's support for the TUS protocol, which divides large files into manageable chunks that can be resumed after interruptions. Here’s an example with tus-js-client:
import * as tus from "tus-js-client";
const upload = new tus.Upload(file, {
endpoint: "https://uploads.pinata.cloud/v3/files",
chunkSize: 50 * 1024 * 1024, // 50MB chunks
retryDelays: [0, 3000, 5000, 10000, 20000],
metadata: { filename: file.name, filetype: file.type },
headers: { Authorization: `Bearer ${process.env.PINATA_JWT}` },
});
upload.start();
This code uses the tus-js-client library to implement resumable file uploads to Pinata’s TUS endpoint by dividing files into 50MB chunks. It includes retry logic to handle interruptions, metadata for file organization, and an authorization header with a Pinata JWT for secure uploads. Progress is tracked in real-time via the onProgress callback, while onSuccess and onError callbacks handle successful uploads and errors, ensuring a seamless and reliable upload process.
3. Add progress indicators
To provide real-time feedback on upload status, use Pinata's onProgress callback. Here’s an example of how to do that:
onProgress: function(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(`Upload progress: ${percentage}%`);
// Update UI here
}
This code uses the onProgress callback from the tus-js-client library to track upload progress by calculating the percentage of bytes uploaded out of the total. This percentage can be logged to the console or used to update a progress bar or other UI elements in real-time, providing transparency during the upload process for improved UX.
4. Handle errors and successful uploads
For success and errors, use retry logic and callbacks. Here’s how:
onSuccess: function() {
console.log("Upload completed successfully");
// Handle success logic
},
onError: function(error) {
console.error("Upload failed:", error);
// Handle error logic
}
The onError callback logs errors and implements retry or user notification logic when an upload fails. The onSuccess callback confirms successful uploads and allows for post-upload actions such as updating the UI or notifying the user, ensuring a smooth and reliable user experience.
Complete example code for resumable upload with progress tracking
This example code will let you implement resumable uploads with progress tracking using the Pinata API and tus-js-client. It includes all the essential steps, including initialization, progress updates, error handling, and finalizing the upload.
// Import the tus-js-client library
import * as tus from "tus-js-client";
// Function to handle resumable uploads with progress tracking
async function resumableUploadWithProgress(file) {
// Initialize the tus.Upload instance
const upload = new tus.Upload(file, {
// Pinata's TUS protocol endpoint for file uploads
endpoint: "https://uploads.pinata.cloud/v3/files",
// Configure the chunk size (50MB in this example)
chunkSize: 50 * 1024 * 1024,
// Retry delays to handle interruptions gracefully
retryDelays: [0, 3000, 5000, 10000, 20000],
// Metadata to associate with the file
metadata: {
filename: file.name, // File name
filetype: file.type, // File MIME type
group_id: "your-group-id", // Optional grouping ID
keyvalues: JSON.stringify({ env: "prod" }) // Custom metadata
},
// Authorization header with your Pinata JWT token
headers: { Authorization: `Bearer ${process.env.PINATA_JWT}` },
// Callback to track and display progress
onProgress: function (bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(`Upload progress: ${percentage}%`);
// Update your progress indicator UI here (e.g., a progress bar)
},
// Callback triggered upon successful upload
onSuccess: function () {
console.log("Upload completed successfully!");
// Handle post-upload logic (e.g., notify the user or process the file)
},
// Callback triggered if an error occurs
onError: function (error) {
console.error("Upload failed:", error);
// Implement error-handling logic (e.g., retry or notify the user)
}
});
// Start the upload process
upload.start();
}
// Example usage: Pass a file object to the function
const inputFile = document.querySelector("#fileInput");
inputFile.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
resumableUploadWithProgress(file);
}
});
Here’s how the key components of the code work:
- chunkSize: Divides the file into manageable chunks, allowing resumption from the last successfully uploaded chunk after an interruption.
- onProgress: Provides live updates on the upload percentage, which can be tied to a UI element like a progress bar or percentage display.
- retryDelays: Defines a retry strategy for interrupted uploads, ensuring robustness against network issues.
- metadata: Allows inclusion of additional information like filename, group_id, and custom key-value pairs to manage files more effectively.
- Authorization: Secures the upload process by including your Pinata JWT token in the request header.
6 best practices to build a reliable upload system
To create a reliable, secure, and user-friendly upload system, we recommend these best practices:
1. Choose the right protocol
Selecting the appropriate protocol depends on the file size and specific requirements of your project.
- For files under 100MB: Use the regular file upload endpoint to handle chunking and resumable uploads automatically.
- For files over 100MB: Implement the TUS protocol. Start by integrating the tus-js-client library and configure the endpoint to Pinata’s TUS URL.
To confirm the protocol selection aligns with upload performance expectations, test with sample files of various sizes.
2. Optimize performance
Use these strategies to fine-tune upload performance:
- Set the chunkSize parameter of the tus-js-client to 50MB. This will optimize performance while avoiding memory overload.
- Implement retry logic using the retryDelays parameter, with incremental backoff times (e.g., 3, 5, 10, 20 seconds). Simulate network failures during testing to validate your retry logic.
- Monitor upload times and server response using tools like browser developer tools or custom logging to identify bottlenecks.
3. Simplify file management with metadata
Metadata helps organize and contextualize uploads, making it easier to retrieve and manage files later. When configuring your upload:
- Include essentials like filename and filetype in the metadata object.
- Use a consistent structure to ensure uniformity across uploads.
- Use descriptive and structured metadata values to enable better file organization and retrieval later in your system.
If you’re uploading files related to specific categories or projects, add identifiers like group_id or custom key-value pairs in JSON format (e.g., { "project": "marketing", "env": "prod" }).
4. Add dynamic elements
To create a simple progress bar UI element that updates dynamically, use the onProgress callback. You can use a library like React Progress Bar or build a custom progress tracker with vanilla JavaScript. For the best possible UX:
- Display user-friendly messages for errors. For example, if a network error occurs, show a message like, “Connection lost. Retrying in 5 seconds...” alongside the progress bar.
- Provide visual confirmation of successful uploads, such as an “Upload Complete!” message or a checkmark icon.
5. Enhance security with JWT authentication
When handling sensitive uploads and user data, security is non-negotiable. When generating JWT tokens securely through your backend:
- Use libraries like jsonwebtoken in Node.js or equivalent for your tech stack. For added security, include a short expiration time.
- Send the JWT token in the Authorization header for each upload request and validate it server-side.
- Rotate signing keys regularly and use environment variables to manage secrets securely.
- Test your implementation with tools like Postman to ensure proper authentication flows.
6. Use Pinata to implement these features
Unlike traditional file upload methods, such as Google Drive's basic resumable uploads, Pinata’s approach excels in simplicity and developer efficiency. Standard methods often require manual handling of chunking and progress monitoring, which can be complex to implement and maintain. Pinata eliminates these barriers by providing a streamlined, developer-friendly experience that integrates seamlessly into projects by offering:
- TUS protocol support for large files: Pinata’s Files API fully supports the TUS protocol, allowing developers to easily handle uploads exceeding 100MB with resumable functionality. The TUS protocol is an open-source, resumable file upload protocol that enables large file uploads to be paused and resumed.
- Resilient upload process: With a chunked upload mechanism, Pinata ensures that file uploads resume from the point of failure, saving bandwidth and preserving user progress.
- Real-time progress tracking and retry mechanisms: The SDK and API offer built-in callbacks for tracking upload progress, giving developers the tools to display progress indicators. Retry logic also ensures interrupted uploads recover gracefully.
Why Pinata is the go-to solution for progress indicators and resumable uploads
Pinata is designed with developers in mind, supporting the TUS protocol and advanced file management. Instead of bogging you down with backend complexities, Pinata’s prebuilt features for chunking, retry logic, and progress tracking, let you focus on delivering exceptional user experiences.
We’ve simplified the integration process with clear documentation and user-friendly tools so you can scale effortlessly.
Start using Pinata for your upload systems today to deliver a more reliable user experience.