Offline-First app using Ionic & PouchDB-CouchDB

Even in today’s hyper-connected world, there will be plenty of times where people need to switch data off to save battery, or simply lose mobile connectivity while traveling. There’s nothing more frustrating for mobile users when losing all connection to an app the second they approach a weak/no network zone. As app makers, we can’t do anything about network systems or smartphone batteries, but we do have control over the way we deliver the offline app experience of our products.
What Is ‘Offline-First’?
The offline-first approach to app development is gaining ever more traction — the logic here is that your app will work beautifully all the time, let it be online or offline — data is downloaded to the user’s device and can still be accessed without an active internet connection.
Recently, I was developing a CRM(Customer Relationship Management) tool and there was an urge for Offline Capability.
Challenges I faced:
I am using Ionic for developing a Hybrid Mobile Application. Ionic provides a Native Plugin, “Ionic Native Storage”, which basically uses the Device Local-Storage to save data in local. It was working perfectly fine in the Development Environment, I was using OnePlus 6 for testing the App. Once deployed to production, the I started facing billions of nightmares.
Basically, what happens is, low end Android Phones cleans up Cache and App Local Storage Data in order to save memory, resulting in losing all the Data stored in the local. Few users faced issue as they use apps like C Cleaner, Clean Master, etc. to clean up cache memories. I might be wrong with this assumption of the root cause of the issue, but this is what I found out after testing the App in multiple conditions.
Also, saving big JSON Arrays in local-storage and the fetching it from there, make the App behave weirdly and at times stuck in processing.
This made the App in a crippled state, when speaking about Offline Capabilities.
Temporary Fix
I some how managed to make the App work, by using some hacks like:
1. Storing very basic and strictly only the data required.
2. Periodically self cleaning the storage programmatically.
3. Asking the User to clean up their storage manually by going to the Phone’s App Manager and clearing up the data every day.
Solution (So far):
I was desperately looking for a Permanent solution. I got two options: i. SQLite, ii. PouchDB-CouchDB
I don’t know why, but I found SQLite a bit “mehhh”..Frustrating/Irritating.
I chose to use PouchDB-CouchDB to solve the problem.
What is PouchDB?
PouchDB is an open source in-browser database API written in JavaScript. It is modelled after CouchDB − a NoSQL database that powers npm. Using this API, we can build applications that work offline and online. PouchDB uses WebSQL and IndexedDB internally to store the data.

Their tagline goes, The Database that Syncs!
And this was exactly what I needed. PouchDB then syncs data automatically to Apache CouchDB, which is again a NoSQL database.
What is CouchDB?
CouchDB lets your data flow seamlessly between server clusters to mobile phones and web browsers, enabling a compelling offline-first user-experience while maintaining high performance and strong reliability.
Implementing this was very simple. I’ll explain it with a short and simple example. I have a module in the App, where I track each and every activity in the App by the User.
For that, first download the CouchDB from its Official Website . Install it and hit the URL in your browser.
http://127.0.0.1:5984/_utils/
This will open up an interface called Futon. This is a built in interface of CouchDB.

Next what you need to do is, create your Database. Its very simple, just click on Create Database, give a name of your Choice and your Voila!.
Data stored in CouchDB are called ‘Documents’. _id is the unique identifier of each document. You can assign your own _id or leave it on couchDB to generate unique hash for every document.
To know more in-depth, visit official documentation of CouchDB.
Now that we have our CouchDB ready, I hope you have your Ionic App ready, waiting to go offline. (To learn about Ionic, visit Ionic Framework).
To install PouchBD in your Ionic App:
npm install pouchdb --save
If you’re using TypeScript, also install
npm install @types/pouchdb --save --save-exact
Create a Provider and add it to your app.module file
import { ActivityTracker } from '../providers/activity-tracker';
and export it under provider. Your app.module file will look something like
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { ActivityTracker } from '../providers/activity-tracker';
@NgModule({
declarations: [
MyApp,
HomePage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, Todos]
})
export class AppModule {}
While trying to connect to CouchDB, you might encounter a CORS (Cross Origin Resource Sharing) issue.
Nothing to worry. Just follow the below steps:
npm install -g add-cors-to-couchdb
Then run:
add-cors-to-couchdb
Now lets make our hands dirty. Add the following code in your Provider:
import { Injectable } from '@angular/core';
import PouchDB from 'pouchdb';
@Injectable()
export class ActivityTracker {
data: any;
db: any;
remote: any;
constructor() {auto_compaction: true
this.db = new PouchDB('crm_activitytracker');
this.remote = 'http://localhost:5984/crm_activitytracker';
//To know more about options, visit pouchdb.com
let options = {
live: true,
retry: true,
continuous: true,
};
this.db.sync(this.remote, options);
}
saveActivity(data) {
data.activityDateTime = moment().format();
data.activity ='Dashboard';
data._id = (moment().unix()).toString();
this.db.put(data).then((resp) => {
console.log(resp);
return resp;
})
.catch((e) => {
console.log(e);
return e;
});
}
}
That’s it. YESSS!! Really, this is it. You can learn about the all the functions of PouchDB from its documentation.
Bonus Tip:
If you have already created a Document with an _id, and want to update it or add some missing fields later or after some operations, using this will throw an error: 409, “Conflict”. As the same _id is already linked to a document.
For that, there is an awesome pluging: “Upsert” (Update or Insert).
This will help you a lot.
To install PouchDB Upsert
npm install pouchdb-upsert
Import this in your Provider
import PouchDB from 'pouchdb';
PouchDB.plugin(require('pouchdb-upsert'));
Now our Provider will look like this:
import { Injectable } from '@angular/core';
import PouchDB from 'pouchdb';
PouchDB.plugin(require('pouchdb-upsert'));
@Injectable()
export class ActivityTracker {
data: any;
db: any;
remote: any;
constructor() {auto_compaction: true
this.db = new PouchDB('crm_activitytracker');
this.remote = 'http://localhost:5984/crm_activitytracker';
//To know more about options, visit pouchdb.com
let options = {
live: true,
retry: true,
continuous: true,
};
this.db.sync(this.remote, options);
}
saveActivity(data) {
data._id = (moment().unix()).toString();
this.db.upsert(data._id, function (doc) {
if(!doc.count){
doc.count = 0;
}
doc.activityDateTime = moment().format();
doc.activity ='Dashboard';
return doc;
console.log(resp);
}).then((resp) => {
console.log(resp);
// success, res is {rev: '1-xxx', updated: true, id: 'myDocId'}
})
.catch((e) => {
console.log(e);
return e;
});
}
}
The doc.count will keep a count on number of retry. It will try forever unless the document gets updated.
Go to PouchDB-Upsert to know about this plugin in details.
So this is all about how I solved the issue, and made the app capable of working offline. PouchDB syncs with CouchDB automatically when there is internet connectivity. So literally you don’t need to do anything for syncing of Data between local device and remote CouchDB.
P.S.: If you have any kind of suggestions or you find any mistake in the above example, feel free to connect with me. You can reach me via email: [email protected] .
Credits:
– Josh Morony: My digital guide when I’m stuck using Ionic. Mainly while I was migrating from Ionic v3 to Ionic v4.
