Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies

Thursday, December 31, 2020

How We Got 50 Thousand Users Within A Month – The Dudeapp Story

 

By the time Facebook became a thing in India and Orkut became history, even though we had no internet connection in our homes, we would go to the nearest cafe to surf through the net, and especially really enjoy all the internet “memes” thoroughly. Inspired by many of the much loved meme/troll pages in Facebook, we decided to start one of our own. We had no experience on running a page and frankly it needed much more attention to get new indulging users/ fan following for the page than I imagined. Our first page got to 7000 likes within a year, I still remember getting 10-30 likes per day and I loved waking up everyday just to check the increase in the audience.

Anyhow, the first page that we created and worked on – like crazy, out of the blue, got hacked. I still don’t like to recollect the moment cause it was one of the few periods that I’d like to forget. But, the passion inside us didn’t die. We learnt a lot from our previous page and we could have easily quit, yet we decided to pursue what we love. We launched our next page with better name, better post and with our experience it got nearly 10,000 likes in three months. Again that page too got hacked.

We took a break from pages as we had no fuel to go further, we tried our luck with YouTube & till date we had no eye on revenue. We pulled of some videos and started to earn from it via Google’s adsense program. That gave us fuel to go further, we started our own humor blog and to market that we started a Facebook page for the same. We were back in action. But unfortunately that page did very bad. It didn’t even get 500 page likes after months of time. Yet, we earned some more & learned way more. we watched videos & read articles on social media marketing and challenges of Entrepreneurship and we decided that we should give people what they want, and then only expect them to help back. With the blog page, we weren’t giving any value to the people but were just pushing links to the page audience. We decided to revamp everything and to have a new beginning.

We thought lot about what people want and how we could differentiate our “page” from all the other mainstream pages. Luckily we ended up deciding to get a “character” for our page who has the personality that we thought the youth would really love to follow. That’s how we created our page “Dude” with “Dude” himself as a stick-man – with a very good sense of humor.Facebook had developed better tools for protecting pages from getting hacked and we opted to use that too. This page, from day one was a hit. We put in some advertising money into the page and boom, we started to get like 20,000 likes per week. We kept intact with our principles rather than pushing links and earning easy money. After three months we hit 100,000 followers. After 5 months we hit million.

After hitting the million point, we had some affiliates and earned good. During this time period Facebook started to reduce all pages reach drastically. We usually got around 10,000 like for every posts started to receive only up to 5,000 to 6,000 likes for each post. Facebook had mainly two agendas:

  1. As there were lots (Billions) of daily active users for Facebook, if its algorithm was in a way that it showed all posts from all the pages that a person has followed/liked to that person’s NewsFeed, it would become too congested. To solve that, Facebook decided to only promote a page’s post to large audience only if the post got very good reaction from initial -“actively following users”.
  2. Apart from the NewsFeed Issue, there came Facebook’s “revenue model” which included the paid promotions through their ad platform. Therefore they reduced all pages reach in order to make publishers to spend more on promoting their content.

At first, we felt frustrated on the reduction of the page’s reach and we were struggling a lot for paid promotions and to get more engagement. At that time we had more than 2.5 million followers. Many similar page owners were going against Facebook and started to quit. But we thought Facebook was not doing anything wrong but only giving other normal users better experience and only fairly practicing their revenue model. All the 2.5 million “followers” weren’t actually our users. It was Zuckerburg’s. His users, therefore he can do what he wants to do with them. This thinking gave rise to the riskiest, most challenging and adventurous phase of our entrepreneurial journey- we decide to create an app for our audience and accumulate our own users & give them better experience than other medias.

We researched about the app market and received lots of quotes from different app building companies. We had a condition of building an app to the at-most perfection in our budget. We had to re-invest almost everything that we had made till date. We got another partner who was ready to brainstorm and to put some more money into the app development. After 3 months of painstaking hardwork, we were ready to release the app. We started the pre-launch marketing through email subscriptions and within 2 days we got more than 6000 people wanting to receive the app. We released the app. “Dudeapp” on early December 2016. There were major bugs with the app, yet we struggled & somehow manged to get them fixed and continued our marketing. Now we have 50,000+ users with plenty of active users & we hope to improve the app drastically in the near future after receiving investments of some sort. The app has been featured in news articles & the Facebooks’ Fbstart mobile app promotion platform has granted us $40,000 worth of tools and services for improving the app. All we have to do now is to push ourselves to the next level by bringing in more features and unparalleled User experience, and I know we’ll somehow achieve that too.

Wednesday, December 2, 2020

How To Build Resilient JavaScript UIs

 

Things on the web can break — the odds are stacked against us. Lots can go wrong: a network request fails, a third-party library breaks, a JavaScript feature is unsupported (assuming JavaScript is even available), a CDN goes down, a user behaves unexpectedly (they double-click a submit button), the list goes on.

Fortunately, we as engineers can avoid, or at least mitigate the impact of breakages in the web apps we build. This however requires a conscious effort and mindset shift towards thinking about unhappy scenarios just as much as happy ones.

The User Experience (UX) doesn’t need to be all or nothing — just what is usable. This premise, known as graceful degradation allows a system to continue working when parts of it are dysfunctional — much like an electric bike becomes a regular bike when its battery dies. If something fails only the functionality dependent on that should be impacted.

UIs should adapt to the functionality they can offer, whilst providing as much value to end-users as possible.

Why Be Resilient #

Resilience is intrinsic to the web.

Browsers ignore invalid HTML tags and unsupported CSS properties. This liberal attitude is known as Postel’s Law, which is conveyed superbly by Jeremy Keith in Resilient Web Design:

“Even if there are errors in the HTML or CSS, the browser will still attempt to process the information, skipping over any pieces that it can’t parse.”

JavaScript is less forgiving. Resilience is extrinsic. We instruct JavaScript what to do if something unexpected happens. If an API request fails the onus falls on us to catch the error, and subsequently decide what to do. And that decision directly impacts users.

Resilience builds trust with users. A buggy experience reflects poorly on the brand. According to Kim and Mauborgne, convenience (availability, ease of consumption) is one of six characteristics associated with a successful brand, which makes graceful degradation synonymous with brand perception.

A robust and reliable UX is a signal of quality and trustworthiness, both of which feed into the brand. A user unable to perform a task because something is broken will naturally face disappointment they could associate with your brand.

Often system failures are chalked up as “corner cases” — things that rarely happen, however, the web has many corners. Different browsers running on different platforms and hardware, respecting our user preferences and browsing modes (Safari Reader/ assistive technologies), being served to geo-locations with varying latency and intermittency increase the likeness of something not working as intended.

Error Equality #

Much like content on a webpage has hierarchy, failures — things going wrong — also follow a pecking order. Not all errors are equal, some are more important than others.

We can categorize errors by their impact. How does XYZ not working prevent a user from achieving their goal? The answer generally mirrors the content hierarchy.

For example, a dashboard overview of your bank account contains data of varying importance. The total value of your balance is more important than a notification prompting you to check in-app messages. MoSCoWs method of prioritization categorizes the former as a must-have, and the latter a nice to have.

If primary information is unavailable (i.e: network request fails) we should be transparent and let users know, usually via an error message. If secondary information is unavailable we can still provide the core (must have) experience whilst gracefully hiding the degraded component.

Wireframe of a banking website. A red icon with error message reads: Sorry, unable to load your bank balance. The top right contains a notification (bell) icon.
When the account balance is unavailable we show an error message. When unread notifications are unavailable we simply remove the count and popup from the UI, whilst preserving the semantic link a href='/notifications' to the notification center. (Large preview)

Knowing when to show an error message or not can be represented using a simple decision tree:

Decision tree with 2 leaf nodes that read (from left to right): Primary error? No: Hide degraded component, Yes: Show error message.
Primary errors should surface to the UI, whereas secondary errors can be gracefully hidden. (Large preview)

Categorization removes the 1-1 relationship between failures and error messages in the UI. Otherwise, we risk bombarding users and cluttering the UI with too many error messages. Guided by content hierarchy we can cherry-pick what failures are surfaced to the UI, and what happen unbeknownst to end-users.

Two wireframes of different error states. The left one titled: Error message per failure, displays 3 red error notifications (1 for each failure). The right one titled: Single error message with action, shows a single error notification with a blue button below.
Just because 3 errors occurred (left) doesn’t automatically mean 3 error messages should be shown. An action, such as a retry button, or a link to the previous page helps guide users what to do next. (Large preview)

Prevention is Better than Cure #

Medicine has an adage that prevention is better than cure.

Applied to the context of building resilient UIs, preventing an error from happening in the first place is more desirable than needing to recover from one. The best type of error is one that doesn’t happen.

It’s safe to assume never to make assumptions, especially when consuming remote data, interacting with third-party libraries, or using newer language features. Outages or unplanned API changes alongside what browsers users choose or must use are outside of our control. Whilst we cannot stop breakages outside our control from occurring, we can protect ourselves against their (side) effects.

Taking a more defensive approach when writing code helps reduce programmer errors arising from making assumptions. Pessimism over optimism favours resilience. The code example below is too optimistic:

const debitCards = useDebitCards();

return (
  <ul>
    {debitCards.map(card => {
      <li>{card.lastFourDigits}</li>
    })}
  </ul>
);

It assumes that debit cards exist, the endpoint returns an Array, the array contains objects, and each object has a property named lastFourDigits. The current implementation forces end-users to test our assumptions. It would be safer, and more user friendly if these assumptions were embedded in the code:

const debitCards = useDebitCards();

if (Array.isArray(debitCards) && debitCards.length) {
  return (
    <ul>
      {debitCards.map(card => {
        if (card.lastFourDigits) {
          return <li>{card.lastFourDigits}</li>
        }
      })}
    </ul>
  );
}

return "Something else";

Using a third-party method without first checking the method is available is equally optimistic:

stripe.handleCardPayment(/* ... */);

The code snippet above assumes that the stripe object exists, it has a property named handleCardPayment, and that said property is a function. It would be safer, and therefore more defensive if these assumptions were verified by us beforehand:

if (
  typeof stripe === 'object' && 
  typeof stripe.handleCardPayment === 'function'
) {
  stripe.handleCardPayment(/* ... */);
}

Both examples check something is available before using it. Those familiar with feature detection may recognize this pattern:

if (navigator.clipboard) {
  /* ... */
}

Simply asking the browser whether it supports the Clipboard API before attempting to cut, copy or paste is a simple yet effective example of resilience. The UI can adapt ahead of time by hiding clipboard functionality from unsupported browsers, or from users yet to grant permission.

Two black and white wireframes. The left one titled: Clipboard unavailable, displays 2 rows of numbers. The right one titled: Clipboard available, shows the same 2 numbers alongside a clipboard icon.
Only offer users functionality when we know they can use it. The copy to clipboard buttons (right) are conditionally shown based on whether the Clipboard API is available. (Large preview)

User browsing habits are another area living outside our control. Whilst we cannot dictate how our application is used, we can instill guardrails that prevent what we perceive as “misuse”. Some people double-click buttons — a behavior mostly redundant on the web, however not a punishable offense.

Double-clicking a button that submits a form should not submit the form twice, especially for non-idempotent HTTP methods. During form submission, prevent subsequent submissions to mitigate any fallout from multiple requests being made.

Two black and white wireframes. The left one titled: Double-click = 2 requests, displays a form and button (labelled submit) above a console showing 2 XHR requests to the orders endpoint. The left one titled: Double-click = 1 request, displays a form and button (labelled submitting) above a console showing 1 XHR request to the orders endpoint.
Users should not be punished for their browsing habits or mishaps. Preventing multiple form submissions because of intentional or accidental double-clicks is easier than cancelling duplicate transactions at a later date. (Large preview)

Preventing form resubmission in JavaScript alongside using aria-disabled="true" is more usable and accessible than the disabled HTML attribute. Sandrina Pereira explains Making Disabled Buttons More Inclusive in great detail.

Responding to Errors #

Not all errors are preventable via defensive programming. This means responding to an operational error (those occurring within correctly written programs) falls on us.

Responding to an error can be modelled using a decision tree. We can either recover, fallback or acknowledge the error:

Decision tree with 3 leaf nodes that read (from left to right): Recover from error? No: Fallback from error?, Yes: Resume as usual. The decision node: Fallback from error? has 2 paths: No: Acknowledge error, Yes: Show fallback.
Decision tree representing how we can respond to runtime errors. (Large preview)

When facing an error, the first question should be, “can we recover?” For example, does retrying a network request that failed for the first time succeed on subsequent attempts? Intermittent micro-services, unstable internet connections, or eventual consistency are all reasons to try again. Data fetching libraries such as SWR offer this functionality for free.

Risk appetite and surrounding context influence what HTTP methods you are comfortable retrying. At Nutmeg we retry failed reads (GET requests), but not writes (POST/ PUT/ PATCH/ DELETE). Multiple attempts to retrieve data (portfolio performance) is safer than mutating it (resubmitting a form).

The second question should be: If we cannot recover, can we provide a fallback? For example, if an online card payment fails can we offer an alternative means of payment such as via PayPal or Open Banking.

Wireframe of a red error notification above a form. The error message reads: Card payment failed. Please try again, or use a different payment method. The text: different payment method is underlined denoting it's a link.
When something goes wrong offering an alternative helps users help themselves, and avoids dead ends. This is especially important for time sensitive transactions such as buying stock, or contributing to an ISA before the tax year ends. (Large preview)

Fallbacks don’t always need to be so elaborate, they can be subtle. Copy containing text dependant on remote data can fallback to less specific text when the request fails:

Two black and white wireframes. The left one titled: Remote data unavailable, displays a paragraph that reads: Make the most of your remaining ISA allowance for the current tax year. The right wireframe titled: Remote data available, shows a paragraph that reads: Make the most of your £16500 ISA allowance for April 2021-2022
UIs can adapt to what data is available and still provide value. The vaguer sentence (left) still reminds users that ISA allowances lapse each year. The more enriched sentence (right) is an enhancement for when the network request succeeds. (Large preview)

The third and final question should be: If we cannot recover, or fallback how important is this failure (which relates to “Error Equality”). The UI should acknowledge primary errors by informing users something went wrong, whilst providing actionable prompts such as contacting customer support or linking to relevant support articles.

Two wireframes, each containing a red error notification. The left one titled: Unhelpful error message, displays the text: Something went wrong. The right one titled: Helpful error message shows a paragraph that reads: Sorry, unable to load your bank balance. Please try again, or. Below the paragraph is a list of the following items, phone us on 01234567890 8am to 8pm Mon to Fri, email us on support at email dot com and search ‘bank balance’ in our knowledge base
Avoid unhelpful error messages. The helpful error message (right) prompts the user to contact CS, including how (phone/ email) and what hours they operate to manage expectations. It’s not uncommon to provide errors with a unique identifier that users can reference when making contact. (Large preview)

Observability #

UIs adapting to something going wrong is not the end. There is another side to the same coin.

Engineers need visibility on the root cause behind a degraded experience. Even errors not surfaced to end-users (secondary errors) must propagate to engineers. Real-time error monitoring services such as Sentry or Rollbar are invaluable tools for modern-day web development.

 A screenshot taken from Sentry’s online sandbox of a TypeError. An error message reads: Cannot read property func of undefined. Below the error is a stack trace of where the exception was thrown
A screenshot of an error captured in Sentry. (Large preview)

Most error monitoring providers capture all unhandled exceptions automatically. Setup requires minimal engineering effort that quickly pays dividends for an improved healthy production environment and MTTA (mean time to acknowledge).

The real power comes when explicitly logging errors ourselves. Whilst this involves more upfront effort it allows us to enrich logged errors with more meaning and context — both of which aid troubleshooting. Where possible aim for error messages that are understandable to non-technical members of the team.

Grey text on white background showing a function logging an error. The 1st function argument reads: Payment Bank transfer – Unable to connect with ${bank}. The 2nd argument is the error. Below the function are 3 labels: Domain, Context, and Problem.
Naming conventions help standardise explicit error messages, which make them easier to find/ read. The diagram above uses the format: [Domain] Context — Problem. You needn’t be an engineer to understand a bank transfer failed, and that the payments teams should investigate (if they aren’t already doing so). (Large preview)

Extending the earlier Stripe example with an else branch is the perfect contender for explicit error logging:

if (
  typeof stripe === "object" &&
  typeof stripe.handleCardPayment === "function"
) {
  stripe.handleCardPayment(/* ... */);
} else {
  logger.capture(
    "[Payment] Card charge — Unable to fulfill card payment because stripe.handleCardPayment was unavailable"
  );
}

Note: This defensive style needn’t be bound to form submission (at the time of error), it can happen when a component first mounts (before the error) giving us and the UI more time to adapt.

Observability helps pinpoint weaknesses in code and areas that can be hardened. Once a weakness surfaces look at if/ how it can be hardened to prevent the same thing from happening again. Look at trends and risk areas such as third-party integrations to identify what could be wrapped in an operational feature flag (otherwise known as kill switches).

Two black and white wireframes. The left one titled: Kill switch off, displays 3 form fields above a blue button. The right one titled: Kill switch on, shows the text: Download PDF next to a download icon.
Not all fallbacks need to be digital. This is especially true for processes that already involve manual steps, such as transferring an ISA from one bank to another. When everything is operational (left) users submit an online form that populates a PDF they print and sign. When the third-party suffers an outage or is down for maintenance (right) a kill switch allows users to download a blank PDF form they can fill in (by hand), print and sign. (Large preview)

Users forewarned about something not working will be less frustrated than those without warning. Knowing about road works ahead of time helps manage expectations, allowing drivers to plan alternative routes. When dealing with an outage (hopefully discovered by monitoring and not reported by users) be transparent.

Wireframe of a blue banner atop of a page. The banner reads: We’re currently experiencing problems with online payments and are working on resolving the issue
Avoid offloading observability to end users. Finding and acknowledging issues before customers do leads to a better user experience. The information banner above is clear, concise, and reassures users that the issue is known about, and a fix is incoming. (Large preview)

Retrospectives #

It’s very tempting to gloss over errors.

However, they provide valuable learning opportunities for us and our current or future colleagues. Removing the stigma from the inevitability that things go wrong is crucial. In Black box thinking this is described as:

“In highly complex organizations, success can happen only when we confront our mistakes, learn from our own version of a black box, and create a climate where it’s safe to fail.”

Being analytical helps prevent or mitigate the same error from happening again. Much like black boxes in the aviation industry record incidents, we should document errors. At the very least documentation from prior incidents helps reduce the MTTR (mean time to repair) should the same error occur again.

Documentation often in the form of RCA (root cause analysis) reports should be honest, discoverable, and include: what the issue was, its impact, the technical details, how it was fixed, and actions that should follow the incident.

Closing Thoughts #

Accepting the fragility of the web is a necessary step towards building resilient systems. A more reliable user experience is synonymous with happy customers. Being equipped for the worst (proactive) is better than putting out fires (reactive) from a business, customer, and developer standpoint (less bugs!).

Things to remember:

  • UIs should adapt to the functionality they can offer, whilst still providing value to users;
  • Always think what can wrong (never make assumptions);
  • Categorize errors based on their impact (not all errors are equal);
  • Preventing errors is better than responding to them (code defensively);
  • When facing an error, ask whether a recovery or fallback is available;
  • User facing error messages should provide actionable prompts;
  • Engineers must have visibility on errors (use error monitoring services);
  • Error messages for engineers/ colleagues should be meaningful and provide context;
  • Learn from errors to help our future selves and others.

 

 

Friday, November 20, 2020

Are you taking responsibility for something you didn’t do?

 

Amazon said you need to admit fault. But do you really?

I didn’t do anything, why should I admit that I did?

In the time I worked with Amazon and while at Riverbend, this is one of the most common statements that I’ve heard from Sellers. It revolves around the mistaken assumption that you have to admit fault when submitting your appeal or Plan of Action. That is not necessarily true.

Don’t take it personally.

Do not take anything that happens with your seller account personally. Everything Amazon does is a business decision. Nobody at Amazon woke up one day and thought “Hmm, let’s get (insert your name here) and ruin their life.” There are millions of sellers on Amazon so most of the actions taken are based on algorithms and automated reviews, there is nothing personal about it.

If you did it, admit it.

If you did what Amazon says, then you need to admit fault. You may not have done it intentionally, but you still did it. Compare this situation to when you get pulled over by the police. They come up to your window and ask you “Do you know why I pulled you over?” They know why they pulled you over, but they want you to admit fault for the situation. You may not have been speeding intentionally, but you still did it. If Amazon takes an action on your account, they know why and they are looking to see what you are going to say. If you are at fault, explain why it happened and how you will prevent it from happening again. There is a difference between guilt and guilt with intent. admit fault

Guilt versus responsibility

If you are not at fault, then you do not have to say you are, but you do have to accept responsibility for what happened. After all, it is your account and Amazon feels you should be responsible for what happens with it.

Sometimes it is the little things that are overlooked then the buyer breaks out their microscope and brings it to Amazon’s attention. Buyers have more free time than ever which means they are scrutinizing the items they receive more closely. They are finding the little scratch that was on their new item.

Was there something you could have done to prevent this? Updating the detail page, a better inspection process for condition, or checking for a Rights Owner.

It is tough to accept responsibility for something that may be out of your control. FBA returns going back into sellable, buyer mistakenly thinking something is inauthentic when it isn’t. These situations are harder to appeal because you, as a seller, may not have done anything wrong but because of a bad buyer experience, your ASIN or account is deactivated.

How can you get that account reinstated?

This is where may sellers try to argue principles with Amazon rather than taking responsibility for their account. Don’t. You may be right but the person who reviews your appeal is not the one who is going to say that Amazon was wrong and reinstate your account nor can they change Amazon policy. If you feel that strongly about something, write to Jeff Bezos at his email address. There is a team that actually reads those emails and acts on them. Sellers are deactivated wrongly, it happens more than it should, but arguing that point with Amazon is not going to get your ASIN or Account reinstated.

Amazon is not out to get you – the seller

 

No, Amazon is NOT targeting sellers

I get it. You’re chugging along, happily selling and following (to the best of your knowledge) Amazon’s policies. Then…

BAM!

Your Account Health Dashboard starts lighting up like the skyline on the Fourth of July.

Your Performance Notifications start piling up.

It can feel like Amazon has you in their crosshairs and have taken time out of their day to focus on making specifically YOUR life difficult.

While still alarming and frustrating, I can assure you that your Seller ID wasn’t pulled out of a hat to be the focus of Amazon’s enforcement arm for the day. Amazon is not targeting sellers.

Let’s go through some of the reasons when and why Amazon enforces policies, and why that can feel like a tsunami wave at times.

Bad press leads to an overreaction or rushes the technical end of Policy and Enforcement Teams

Amazon hates bad press. The Risk Mitigation teams (i.e. the Policy arm behind the enforcement teams) are hard pressed to move fast when bad press unearths a vulnerability in Amazon’s policy and policing of Third-Party Sellers or the catalog.

Are these Risk Mitigation teams generally full of smart, thoughtful people? Yes. Are they staffed with incredibly talented software engineers? Absolutely. However, asking multiple teams to roll out new enforcement (which entails a manual audit, code creation, creating externally facing policy, and training front-line investigators) in a matter of 24-72 hours is error prone. Amazon has a Leadership Principal called “Bias for Action” and rolling out half-baked policy or enforcement changes on a tight timeline is the lived version of this philosophy.

Amazon is not targeting sellers

Enforcement “Bots” and other policies are rarely reviewed for possible abuse by bad actors

Have you ever gotten a slew of fraudulent Notices of Claimed Infringement from non-existent “Rights Owners”?

Have you had your products taken down and received warnings because a competitor has found which keywords to leave in feedback or Product Reviews to game the system?

It feels like an overwhelming battle to convince Amazon that these actions are due to malicious intent for a reason. Amazon built these systems with the underlying belief that those parties complaining are honest. It’s rarely- if ever- considered as to if the system used to police third party sellers can be used in a manner for which it was NOT intended.

In my time working for these teams I do not recall a single internal policy that require investigators evaluate the veracity of the complaint or the honesty of the complainant.

Bad apples spoil the barrel

Amazon knows that, when a buyer is burned by a Third Party Seller, they buy less over the course of their “Customer Lifetime”. So, they try to focus on preventing dissatisfied customers by looking at past bad actor Sellers and use their behavior to try and predict when other sellers might “go bad” and put friction in place in an attempt to weed out the bad guys. The problem with this “shoot first, ask questions later” method is that a LOT (and I mean a LOT) of bad-guy behavior prior to actually engaging in bad deeds looks an AWFUL lot like standard selling behavior.

Have you ever been asked to supply evidence of your identity? Perhaps evidence that a new product you have added to your listings is genuine even before you have made your first sale? Well, those bad guys are to blame. Somewhere, a bad guy has used a false or stolen identity and has sold a fake version of your widget.

Amazon is constantly playing catch-up to those bad actors while trying to predict the future so that the same bad guy behavior does not repeat simultaneously. Make no mistake, the Enforcement and Policy teams have little to no concern how these proactive measures might hurt your business. Their ONLY goal is risk mitigation (e.g. reducing bad press) and a positive buyer experience. All of this is measured with metrics, like “reducing complaints about product condition by X% Year over Year”. There are NO metrics within the enforcement arms that look at, “Sellers that Abandoned Amazon after enforcement.” In fact, sellers that DO end up abandoning Amazon are generally assumed to be bad guys that Amazon has somehow scared off.

Technical Timelines often have coinciding launches

Amazon typically does not coordinate enforcement launches between different enforcement groups to ensure that they do not overlap. The Safety team doesn’t care if or when the Seller Fulfilled Prime team launches enforcement and vice versa. And, like nearly all business, big product (e.g. enforcement) launches are scheduled quarterly. In addition, there are several periods of “Code Freeze” at Amazon, meaning that there will always inevitably be teams that launch changes RIGHT at the last minute concurrently.

In conclusion, while we know that this doesn’t remove any frustration, we do hope that it sheds some light on why it can feel like policy infractions are doled out inconsistently and in waves. Rest easier knowing Amazon is not targeting sellers.

Thursday, November 19, 2020

Third-party Amazon sellers should monitor returns carefully or risk buyer complaints Curling irons with someone else’s hair in them. Mouthwash with broken seals. Coffee makers with smelly old moldy coffee inside. These are only a few of the disgusting surprises that FBA sellers have experienced. Why? Because Amazon’s FBA returns handling processes are – to put it kindly – lacking. Third-party Amazon sellers should monitor returns What happens when customers return items to FBA? One reason buyers love Amazon is the friendly returns policy for FBA purchases. Amazon makes it easy for customers, who can take a look at their mail-order item and decide to send it on back. Unfortunately, buyers don’t always return items in new condition. This might mean torn packaging, broken seals, or even used items. When an order is sent back to the FBA warehouse, Amazon personnel are supposed to inspect it carefully. They are charged with determining if the item is still in “new” condition. If so, it is placed into the seller’s fulfillable inventory. If not, it is placed in unfulfillable. A third possible scenario involves Amazon repackaging the item. This happens when the product is in new condition, but the packaging is not. Amazon reserves the right to repackage it and place it back into fulfillable inventory. (The setting that once allowed sellers to turn off repackaging has been taken away. Sorry, folks, you’re stuck with it.) Amazon’s warehouse employees are graded on the number of transactions they conduct per hour. Human nature dictates that this leads to inaccuracy as employees try to meet or beat the required work level. Of course, quality naturally suffers, and items that should never be placed into fulfillable inventory are re-sold. Another problem occurs when Amazon puts returns in fulfillable from categories that are supposed to be disposed of or not required to be mailed back to the warehouse. Supplements are a good example. These items should never be put back into fulfillable, but often are anyway. What can 3P sellers do to protect themselves? The most worrisome scenarios with bad returns involve products that a 3P seller stocks over the long term. Therefore, the higher volume you sell over time, the more potentially bad returns are sent back to the Amazon warehouse. There are a few strategies that 3P sellers can employ to combat the problem: For private-label products, add a printed seal. Include language such as “if seal is broken, item is not new.” This seal is not for buyers. It’s for personnel on Amazon’s FBA returns processing teams. This way, they will be more likely to place an opened item into unfulfillable inventory. Sell down or sell through. For products you replenish, allow your stock to sell through. Alternatively, sell it down and then place a removal order for the remaining units. In the meantime, restock with a different SKU. This way, bad stock being resold multiple times will be removed from the FBA warehouse.

 

Working the appeals system with a skilled Amazon consultant creates better results

When my Amazon seller account is suspended, should I hire a lawyer? No. An attorney should not be your first call.

It’s an understandable knee-jerk reaction to start searching for a legal eagle. After all, Amazon has all the resources in the world. In other kinds of disputes, attack-dog lawyers are a great option for companies that need a fighter on their side.

But an Amazon suspension – whether for an account or an ASIN – is a very different animal from a lawsuit. Plus, there are several reasons that hiring an attorney early in the process can actually make it less likely you will be successful in your dealings with Amazon.

Should I hire a lawyer?

Legal eagles don’t fly in reinstatement appeals

There are a few simple reasons that attorneys do not make good Amazon appeal writers:

  1. A key element to any account appeal or ASIN appeal is an admission of guilt. Amazon wants to know what you did wrong. Lawyers are opposed to admitting guilt – even if you were wrong. They are concerned that an admission of wrongdoing would hurt their client in future litigation. But without the admission, reinstatement will almost never happen.
  2. Lawyers make threats and demands. Instead of going through the appeals process, some attorneys encourage sellers to send demand letters to Amazon’s legal department. This is a tremendous mistake. If you approach Amazon Legal instead of going through standard appeals channels, Amazon is very likely to stop communicating with you. Any future appeals you submit would be completely ignored.
  3. Attorneys are not e-commerce consultants. For many appeal types, it’s critical that you correct failed business processes. The best appeal writers have experience with business processes and e-commerce. They know how to help your company identify gaps, update your SOPs and explain the results to Amazon.
  4. Lawyers haven’t worked inside the Amazon machine. Ideally, your appeal should be written by somebody with an in-depth understanding of Amazon’s thinking, SOPs and structure. Teams that include ex-Amazon employees from Seller Performance and Seller Support can provide insight and guidance that a law firm cannot. Plus, Amazon consultants know how to work multiple channels inside of Amazon to solve your problems.
  5. You cannot sue Amazon. With very limited exceptions, third-party sellers cannot file lawsuits against Amazon. This is part of the Business Solutions Agreement (BSA), which governs the relationship between the two parties. 

When should I hire a lawyer??

There are some limited circumstances where third-party sellers should I hire a lawyer? to protect their interests on the platform:

  1. Intellectual property complaints can be difficult. Oftentimes, an Amazon consulting company like Riverbend can help you appeal these successfully. But in limited circumstances, you may need an attorney to defeat a complaint made against your company. Keep in mind, in these cases the attorney isn’t fighting Amazon on your behalf. Rather, the lawyer communicates with the alleged rights owner to try and convince them to remove their complaint. Or, in some cases, a lawsuit against the alleged rights owner may be necessary. This is particularly true for patent claims.
  2. Sometimes, mediation is the end game. If the appeals process fails – both internally at Amazon and externally with government and quasi-government agencies – it’s time for mediation. This is allowed under the BSA. Some sellers choose to attack the mediation process themselves or with the help of a consultant. Others with a lot of money at stake should I hire a lawyer to help with the process.

Wednesday, November 18, 2020

The many kinds of intellectual property violations on Amazon

 

Intellectual property violations on Amazon run the gamut, but all put your seller account at risk

Intellectual property rights are taken seriously. Why? Because intellectual property violations on Amazon can turn into a legal issue. 

When it comes to Intellectual Property (IP), Amazon protects itself. And to protect itself, Amazon gives the benefit of the doubt to the alleged Rights Owner. If a Rights Owner (RO) made a complaint that their IP was violated, and Amazon did not act, Amazon would be legally liable. 

Unfortunately, this creates terrible headaches for Amazon sellers who are often incorrectly warned – and even suspended – over trademark, copyright, patent and counterfeit claims. 

intellectual property violations on Amazon

Standard IP complaints on Amazon

Trademark is one of the most commonly filed IP complaints. A trademark is a legally registered symbol or word(s) that is used for representing a product or company. If an RO has a registered and active trademark, and is being shown on someone else’s detail page or product, enforcement can occur.

This can also happen with a Common Law Trademark (unregistered trademark). Amazon will warn sellers for Common Law Trademarks when the trademark can be verified. This means the trademark must be known in the region it is being reported, and it must be associated with the RO.

Copyright infringement means that the RO’s work is being used without permission. This applies to a picture, book, film, song and many other forms of media. On Amazon, this complaint is more likely to occur with images. If an RO can show that there is a violation by providing information about the work or the copyright registration number, the seller will be warned. Technically speaking, the media does not need to be registered at all.

There are two types of patents that can be reported to Amazon. These are design patent and utility patent. To put it simply, a design patent is for the visual qualities of a product. A utility patent will protect the functionality of a product. A valid, registered and active patent must match a supposedly infringing product. Dealing with a patent infringement issue can be very difficult. It may be best to seek legal advice if the situation occurs.

The most common IP complaint: counterfeit

The most common infringement type that a seller may face is for counterfeit product claims. For an RO to report a counterfeit claim, they must have a registered and active trademark. The trademark must be seen on the product, and the RO must be claiming the products are fake or counterfeit. Frequently, an RO will declare exclusive distribution when supporting their counterfeit claim. Amazon clearly states that they will not support an exclusive distribution claim. Therefore, it would be useful for sellers to look out for exclusive distribution when attempting to contact an RO.

What to do when IP complaints are filed

In conclusion, all of these intellectual property claims can cause headaches for sellers. But with the right knowledge, you can gain reinstatement for your account or ASIN. Even though Amazon is looking to protect itself and the RO, all sellers deserve a chance to appeal infringement warnings. Proper advice can help the seller move past the issue and prevent future enforcements.

Most importantly, don’t ignore IP complaints. Address them head-on. If Amazon thinks you are not serious about these and other warnings, you are at much higher risk of losing your selling privileges — maybe permanently.

Friday, November 13, 2020

What does the explosion in Amazon related account suspensions mean for you?

 

Some related account suspensions are Amazon errors, some are ancient history

A flood of related account Amazon suspensions has sellers wondering what is going on. Unfortunately, the answer isn’t a simple one. Earlier this year, Amazon changed its policy about multiple accounts. Before, if a seller wanted more than one Amazon account, they had to request approval and follow a set of simple rules. The most important of these rules was that the accounts could not sell the same inventory.
With the policy change earlier this year, Amazon said no advance permission was now necessary. However, sellers with more than one account must have a valid business reason for doing so. Plus, Amazon explicitly stated that if one account is suspended for whatever reason, Amazon reserves the right to suspend all of the accounts that seller owns.
 
Since that time, we have seen a rash of accounts going down for “related” or “linked” accounts. In some cases, these are real linkages. For example, we have sellers who owned a different account a long time ago and it was suspended, or they worked for another Amazon business and that created a linkage.
In other cases, our clients are being caught up in false positives. For whatever reason, Amazon thinks there is a link – but there honestly is not. Finally, in some cases, Amazon makes a tremendous mistake. They suspend a seller for having an account in another marketplace – be it Canada, Japan or elsewhere. These are flat-out technology errors on Amazon’s part. Appeals for related account typically require an escalation for reinstatement. Unfortunately, front-line Seller Performance does not feel empowered to turn these accounts back on.

Your best strategy?

  1. Make sure there are no linkages between your Amazon account and another selling account, such as account owners, tax ID numbers, bank accounts, credit cards, IP addresses, warehouse addresses, etc.
  2. If you have more than one account, ensure you have a valid business reason for doing so. This might be using one account for private-label products and another for goods purchased via wholesale. Or, some sellers are developing multiple brands on separate accounts.
  3. If you have more than one account, never sell the same inventory. Stay away from offering the same items, brands or – if possible – categories.
  4. If your account is suspended for related accounts, be ready to provide a reasonable explanation – even if you’re guessing.
  5. Be ready to offer detailed verification information about your account.

Thursday, November 12, 2020

Amazon’s acronym language explained

 

New sellers can get lost in the abbreviations

Amazon loves to use acronyms. They are a part of Amazon’s love language and are used daily. This is something that you may notice when interacting with Amazon or even reading through the Seller Forums. Numerous Amazon acronyms are commonly used and we’ve gathered a few that every seller should know. This list has been compiled for you and will hopefully help you navigate Amazon. Especially for you newer sellers out there.

Amazon acronyms from A-Z:

Amazon acronyms as explained

3P – Third-Party Seller

A third party seller uses inventory they have purchased to sell to consumers on Amazon

AMZ – Amazon

The acronym is a more simple way to say Amazon.

ACOS – Advertising Cost Of Sale

This represents the percentage of sales that was spent on advertising.

API – Application Program Interface

The code that allows software programs to communicate with each other.

ASIN – Amazon Standard Information Number

All products on Amazon will have an ASIN.

ASP – Average Selling Price

The net sales divided by the number of products sold will get you the ASP.

AWS – Amazon Web Services

A subsidiary of Amazon that provides cloud platform and API services.

B2B – Business to Business

Unlike business to customers, the service is for business to business.

BB – Buy Box

This is the box where buyers see the button to purchase products.

BOGO -Buy One, Get One (Free)

This is a great promotional deal that allows you to offer two products for the price of one.

BSM – Buyer-Seller Messages

The messages between the customer and the seller.

BSR – Best Seller Rank

The rank of the item in a category.

DP – Detail Page

The page for the product.

DSP – Demand Slide Platform

This represents the display advertising service.

EAN – European Article Number

A 23 digit number for retail products in Europe.

EBC – Enhanced Brand Content

The detail page description and show enhances content like images.

FBA – Fulfilled By Amazon

The program where Amazon is responsible for storing products and shipping them to buyers.

FBM – Fulfilled By Merchant

The seller is responsible for the inventory storing and fulfilling orders.

FC – Fulfillment Center

Amazon’s storage facility where orders are fulfilled.

FNSKU – Fulfillment Network Stock Keeping Unit

Amazon’s unique identifier used to label units in the fulfillment centers.

GTIN – Global Trade Item Number

A unique 14 digit number used globally to identify products and services.

IP – Intellectual property

Property that is protected such as trademarks, patents, copyrights.

ISBN – International Standard Book Number

A 13 digit number to identify individual books.

MAP – Minimum Advertised Price

The price is determined by a manufacturer. Sellers will be instructed to not sell the product below that price.

MCF – Multi-Channel Fulfillment

Inventory that is stored and fulfilled by Amazon but the order is from another sales channel.

MSRP – Manufacturer’s Suggested Retail Price

This is to keep prices similar for different stores, sales channels, platforms, etc.

ODR – Order Defect Rate

A performance metric based on the percentage of orders with defects such as A-to-z claims and negative feedback.

OOS – Out Of Stock

Items are no longer in stock.

OTC – Over The Counter

Products that do not need a prescription to purchase.

POA – Plan Of Action

When seller accounts or ASINs are suspended, Amazon frequently requests a Plan of Action from the seller explaining what happened – and how they will stop it from happening again.

PL – Private label

Sellers may have a brand but have a manufacturer. These are the suppliers’ products but they do not make them.

Q1 – First Quarter

The portion of the year including January, February and March.

Q2 – Second Quarter

The months of April, May and June of each year.

Q3 – Third Quarter

This includes July, August and September of a calendar year.

Q4 – Fourth Quarter

Busy months for retail. Q4 includes the last three months (October, November and December) of the year.

QA – Quality Assurance

To ensure the desired quality of the service and/or product.

SC – Seller Central

The seller portal for the Amazon marketplace. Amazon Seller Central

SFP – Seller Fulfilled Prime

The program where sellers must meet Amazon’s Prime requirements.

SKU – Stock Keeping Number

The code to identify a product.

SLA – Service Level Agreement

The agreement details the expected level of service.

TOS – Terms Of Services

The rules and regulations that the seller must follow.

UPC – Universal Product Code

A 12-digit code is associated with the barcode of a product.

VAT – Value Added Tax

For products sold in the United Kingdom and Europe. This is a consumption tax levied on products at each and every point of sale in which value was added.

Wednesday, November 4, 2020

SWR: React Hooks For Remote Data Fetching

 

SWR is a lightweight library created by Vercel (formerly ZEIT) that allows fetching, caching, or refetching data in realtime using React Hooks. It’s built with React Suspense which lets your components “wait” for something before they can render, including data. SWR ships also with great features such as dependent fetching, focus on revalidation, scroll position recovery, and so on. It’s also a very powerful tool since it’s backend agnostic and has good support for TypeScript. It’s a package that has a bright future.

Why should you care? You should care if you’ve been looking for a library that does not only fetch data from APIs but also make it possible to do things like caching and dependent fetching. What will be covered in this tutorial will come in handy when building React applications with a lot of moving parts. It’s expected that you should have made use of Axios and the Fetch API, even though we’ll compare how they differ from SWR, we won’t be going into details on how they’ll be implemented.

In this guide, I will introduce you to React Hooks for Remote Data Fetching by building a Pokedex app that requests data from the Pokemon API. We will also dive into other features that come with SWR as well, and highlight its differences compared to popular solutions such as the Fetch API and the Axios library and give you the reasons why using this library and why you should keep an eye on SWR.

So, let’s start by answering a fundamental question: What is SWR?

 

What Is SWR?

SWR is an initialism of stale-while-revalidate. It’s a React Hooks library for remote data fetching. SWR works with three main steps: first, it returns the data from the cache (the stale part), then sends the fetch request (the revalidate part), and finally comes with the up-to-date data. But no worries, SWR handles all these steps for us. The only thing we have to do is give the useSWR hook the needed parameters to make the request.

SWR has also some nice features such as:

  • Back-end agnostic
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Request deduplication
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Lightweight.

Sounds magical? Well, SWR simplifies things and increases for sure the user experience of your React app. And once we start implementing it in our project, you will see why this hook is handy.

It’s important to know that the name of the package is swr or SWR and the hook used to get SWR features is named useSWR.

In theory, the SWR is maybe what you need to enhance your data fetching. However, we already have two great ways of making HTTP requests in our app: the Fetch API and the Axios library.

So, why using a new library to retrieve data? let’s try answering this legit question in the next section.

Comparison With Fetch And Axios

We already have many ways to make HTTP requests in our React Apps, and two of the most popular is the Fetch API and the Axios library. They are both great and allows us to fetch or send data easily. However, once the operation is done, they will not help us to cache or paginate data, you have to do it on our own.

Axios or Fetch will just handle the request and return the expected response, nothing more.

And compared to SWR, it’s a bit different because the SWR under the hood uses the Fetch API to request data from the server — it’s kind of a layer built on top of it. However, it has some nice features such as caching, pagination, scroll position recovery, dependent fetching, etc, and to be precise a certain level of reactivity out of the box that Axios or Fetch do not have. It’s a big advantage because having such features help to make our React Apps fast and user-friendly and reduce markedly the size of our code.

And to conclude, just keep in mind that SWR is not the same as Axios or Fetch even if it helps to deal with HTTP requests. SWR is more advanced than them, it provides some enhancements to keep our app synchronized with the back-end and hence increases the performance of our app.

Now we know what’s differences SWR has compared to the Axios library or the Fetch API, it’s time to dive into why using such a tool

 

Why Using SWR For Data Fetching?

As I said earlier SWR ships with some handy features that help to increase the usability of your app easily. With SWR, you can paginate your data in no-time using useSWRPages, you can also fetch data that depends on another request or recover a scroll position when you get back to a given page, and so much more.

Usually, we show to the user a loading message or a spinner while fetching data from the server. And with SWR, you can make it better by showing to the user the cached or stale data while retrieving new data from the API. And once that operation is done, it will revalidate the data to show the new version. And you don’t need to do anything, SWR will cache the data the first time you fetch it and retrieve it automatically when a new request is made.

So far, we already see why using SWR over Axios or Fetch is better depending obviously on what you are aiming to build. But for many cases, I will recommend using SWR because it has great features that go beyond just fetching and returning data.

That said, we can now start building our React app and use the SWR library to fetch remote data.

So, let’s start by setting up a new project.

Setting Up

As I said earlier in the introduction, we will build an app that fetches data from the Pokemon API. You can use a different API if you want too, I will stick with it for now.

And to create a new app, we need to run the following command on the terminal:

npx create-react-app react-swr

Next, we need to install the SWR library by first navigating to the folder that holds the React app.

cd react-swr

And run on the terminal the following command to install the SWR package.

yarn add swr

Or if you’re using npm:

npm install swr

Now we have all set up done, let’s structure the project as follow to start using SWR:

src
├── components
|  └── Pokemon.js
├── App.js
├── App.test.js
├── index.js
├── serviceWorker.js
├── setupTests.js
├── package.json
├── README.md
├── yarn-error.log
└── yarn.lock

As you can see, the folder structure is simple. The only thing to notice is the components folder that holds the Pokemon.js file. It will be used later as a presentational component to show a single Pokemon once we get data from the API.

Great! With that in place, we can now start fetching data from the API using useSWR.

Fetching Remote Data

The SWR package has some handy features as we have seen above. However, there are two ways of configuring this library: either locally or globally.

A local setup means that every time we create a new file, we have to setup SWR again to be able to fetch remote data. And a global setup allows us to reuse a part of our configuration within different files because a fetcher function can be declared once and used everywhere.

And no worries, we will see both in this article, but for now, let’s get hands dirty and add some meaningful code in the App.js file.

Displaying The Data

import React from 'react'
import useSWR from 'swr'
import { Pokemon } from './components/Pokemon'

const url = 'https://pokeapi.co/api/v2/pokemon'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

function App() {
    const { data: result, error } = useSWR(url, fetcher)

    if (error) return <h1>Something went wrong!</h1>
    if (!result) return <h1>Loading...</h1>

    return (
        <main className='App'>
            <h1>Pokedex</h1>
            <div>
                {result.results.map((pokemon) => (
                    <Pokemon key={pokemon.name} pokemon={pokemon} />
                ))}
            </div>
        </main>
    )
}
export default App

As you can see, we start by importing useSWR from the SWR library. This declares the URL of the API you want to get data from, and a function to fetch these data.

The function fetcher is used here to transform the data into JSON. It receives the data fetched as an argument and returns something.

Notice that here, I use the Rest operator ((...args)) since I’m not sure of the type and length of data received as a parameter, therefore, I copy everything before passing it again as an argument to the fetch method provided by useSWR which transforms the data into JSON and returns it.

That said, the fetcher and the url of the API can be now passed as parameters to the useSWR hook. With that, it can now make the request and it returns two states: the data fetched and an error state. And data: result is the same as data.result, we use object destructuring to pull result from data.

With the returned values, we can now check if the data is successfully fetched and then loop through it. And for each user, use the Pokemon component to display it.

Now we have the data and pass it down to the Pokemon Component, it’s time to update Pokemon.js to be able to receive and display the data.

Creating The Pokemon Component

import React from 'react'
import useSWR from 'swr'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

export const Pokemon = ({ pokemon }) => {
    const { name } = pokemon
    const url = 'https://pokeapi.co/api/v2/pokemon/' + name

    const { data, error } = useSWR(url, fetcher)

    if (error) return <h1>Something went wrong!</h1>
    if (!data) return <h1>Loading...</h1>

    return (
        <div className='Card'>
            <span className='Card--id'>#{data.id}</span>
            <img
                className='Card--image'
                src={data.sprites.front_default}
                alt={name}
            />
            <h1 className='Card--name'>{name}</h1>
            <span className='Card--details'>
                {data.types.map((poke) => poke.type.name).join(', ')}
            </span>
        </div>
    )
}

Here, we have a component that receives a single Pokemon data from the API and displays it. However, the data received does not contain all fields needed, hence we have to make another request to the API to get the complete Pokemon object.

And as you can see, we use the same process to retrieve the data even if this time we append the name of the Pokemon to the URL.

By the way, if you are not familiar with destructuring, ({ pokemon }) is the same as receiving props and accessing to the pokemon object with props.pokemon. It’s just a shorthand to pull out values from objects or arrays.

With that in place, if you navigate to the root folder of the project and run on the terminal the following command:

yarn start

Or if you’re using npm:

npm start

You should see that the data are successfully fetched from the Pokemon API and displayed as expected.

Great! We are now able to fetch remote data with SWR. However, this setup is a local one and can be a bit redundant because you can already see that App.js and Pokemon.js use the same fetcher function to do the same thing.

But luckily, the package comes with a handy provider named SWRConfig that helps to configure SWR globally. It’s a wrapper component that allows child components to use the global configuration and therefore the fetcher function.

To setup SWR globally, we need to update the index.js file because it’s where the App component is rendered using React DOM. If you want, you can use SWRConfig directly in the App.js file.

Configuring SWR Globally

import React from 'react'
import ReactDOM from 'react-dom'
import { SWRConfig } from 'swr'
import App from './App'
import './index.css'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

ReactDOM.render(
    <React.StrictMode>
        <SWRConfig value={{ fetcher }}>
            <App />
        </SWRConfig>
    </React.StrictMode>,
    document.getElementById('root')
)

As you can see, we start by importing SWRConfig which is a provider that needs to wrap the higher component or just part of your React app that needs to use SWR features. It takes as props a value that expects an object of config. You can pass more than one property to the config object, here I just need the function to fetch data.

Now, instead of declaring the fetcher function in every file, we create it here and pass it as value to SWRConfig. With that, we can now retrieve data at any level in our app without creating another function and hence avoid redundancy.

Besides that, fetcher is equal to fetcher: fetcher, it’s just syntactic sugar proposed by ES6. With that change, we need now to update our components to use the global config.

Using The Global SWR Config

import React from 'react'
import useSWR from 'swr'
import { Pokemon } from './components/Pokemon'

const url = 'https://pokeapi.co/api/v2/pokemon'

function App() {
    const { data: result, error } = useSWR(url)

    if (error) return <h1>Something went wrong!</h1>
    if (!result) return <h1>Loading...</h1>

    return (
        <main className='App'>
            <h1>Pokedex</h1>
            <div>
                {result.results.map((pokemon) => (
                    <Pokemon key={pokemon.name} pokemon={pokemon} />
                ))}
            </div>
        </main>
    )
}
export default App

Now we only need to pass the url to useSWR, instead of passing the url and fetcher method. Let’s also tweak the Pokemon component a bit.

import React from 'react'
import useSWR from 'swr'

export const Pokemon = ({ pokemon }) => {
    const { name } = pokemon
    const url = 'https://pokeapi.co/api/v2/pokemon/' + name

    const { data, error } = useSWR(url)

    if (error) return <h1>Something went wrong!</h1>
    if (!data) return <h1>Loading...</h1>

    return (
        <div className='Card'>
            <span className='Card--id'>#{data.id}</span>
            <img
                className='Card--image'
                src={data.sprites.front_default}
                alt={name}
            />
            <h1 className='Card--name'>{name}</h1>
            <span className='Card--details'>
                {data.types.map((poke) => poke.type.name).join(', ')}
            </span>
        </div>
    )
}

You can already see that we have no fetcher function anymore, thanks to the global configuration which passes the function to useSWR under the hood.

Now, you can use the global fetcher function everywhere in your app. The only thing that the useSWR hook needs to fetch remote data is the URL.

However, we can still enhance the setup furthermore by creating a custom hook to avoid declaring the URL again and again, and instead, just pass as parameter the path.

Advanced Setup By Creating A Custom Hook

To do so, you have to create a new file in the root of the project named useRequest.js (you can name it whatever you want) and add this code block below to it.

import useSwr from 'swr'

const baseUrl = 'https://pokeapi.co/api/v2'

export const useRequest = (path, name) => {
    if (!path) {
        throw new Error('Path is required')
    }

    const url = name ? baseUrl + path + '/' + name : baseUrl + path
    const { data, error } = useSwr(url)

    return { data, error }
}

Here, we have a function that receives a path and optionally a name and appends it to the base URL to build the complete URL. Next, it checks if a name parameter is received or not and handle it consequently.

Then, that URL is passed as a parameter to the useSWR hook to be able to fetch the remote data and return it. And if no path is passed, it throws an error.

Great! we need now to tweak the components a bit to use our custom hook.

import React from 'react'
import { useRequest } from './useRequest'
import './styles.css'
import { Pokemon } from './components/Pokemon'

function App() {
    const { data: result, error } = useRequest('/pokemon')

    if (error) return <h1>Something went wrong!</h1>
    if (!result) return <h1>Loading...</h1>

    return (
        <main className='App'>
            <h1>Pokedex</h1>
            <div>
                {result.results.map((pokemon) => (
                    <Pokemon key={pokemon.name} pokemon={pokemon} />
                ))}
            </div>
        </main>
    )
}
export default App

Now, instead of using the SWR hook, we use the custom hook built on top of it and then pass as expected the path as an argument. With that in place, everything will work like before but with a much cleaner and flexible configuration.

Let’s also update the Pokemon component.

import React from 'react'
import { useRequest } from '../useRequest'

export const Pokemon = ({ pokemon }) => {
    const { name } = pokemon
    const { data, error } = useRequest('/pokemon', name)

    if (error) return <h1>Something went wrong!</h1>
    if (!data) return <h1>Loading...</h1>

    return (
        <div className='Card'>
            <span className='Card--id'>#{data.id}</span>
            <img
                className='Card--image'
                src={data.sprites.front_default}
                alt={name}
            />
            <h1 className='Card--name'>{name}</h1>
            <span className='Card--details'>
                {data.types.map((poke) => poke.type.name).join(', ')}
            </span>
        </div>
    )
}

You can already see how our custom hook makes things easier and more flexible. Here, we just need to pass additionally the name of the Pokemon to fetch to useRequest and it handles everything for us.

I hope you start enjoying this cool library — However, we still have things to discover because SWR offers so many features, and one of them is useSWRPages which is a hook to paginate data easily. So, let’s use that hook in the project.

Paginate Our Data With useSWRPages

SWR allows us to paginate data easily and request only a part of it, and when needed refetch data to show for the next page.

Now, let’s create a new file in the root of the project usePagination.js and use it as a custom hook for pagination.

import React from 'react'
import useSWR, { useSWRPages } from 'swr'
import { Pokemon } from './components/Pokemon'

export const usePagination = (path) => {
    const { pages, isLoadingMore, loadMore, isReachingEnd } = useSWRPages(
        'pokemon-page',
        ({ offset, withSWR }) => {
            const url = offset || `https://pokeapi.co/api/v2${path}`
            const { data: result, error } = withSWR(useSWR(url))

            if (error) return <h1>Something went wrong!</h1>
            if (!result) return <h1>Loading...</h1>

            return result.results.map((pokemon) => (
                <Pokemon key={pokemon.name} pokemon={pokemon} />
            ))
        },
        (SWR) => SWR.data.next,
        []
    )

    return { pages, isLoadingMore, loadMore, isReachingEnd }
}

As you can see, here we start by importing useSWRPages which is the helper that allows paginating data easily. It receives 4 arguments: the key of the request pokemon-page which is also used for caching, a function to fetch the data that returns a component if the data are successfully retrieved, and another function that takes the SWR object and request data from the next page, and an array of dependencies.

And once the data fetched, the function useSWRPages returns several values, but here we need 4 of them: the pages that is the component returned with the data, the function isLoadingMore which checks if the data are currently fetched, the function loadMore that helps fetching more data, and the method isReachingEnd which determines whether there is still data to retrieve or not.

Now we have the custom hook that returns the needed values to paginate data, we can now move to the App.js file and tweak it a bit.

import React from 'react'
import { usePagination } from './usePagination'
import './styles.css'

export default function App() {
    const { pages, isLoadingMore, loadMore, isReachingEnd } = usePagination(
        '/pokemon'
    )

    return (
        <main className='App'>
            <h1>Pokedex</h1>
            <div>{pages}</div>
            <button
                onClick={loadMore}
                disabled={isLoadingMore || isReachingEnd}
            >
                Load more...
            </button>
        </main>
    )
}

Once the usePagination hook imported, we can now pass the path as a parameter and get back the returned values. And since pages is a component, we don’t need to loop through the data or anything like that.

Next, we use the function loadMore on the button to fetch more data and disable it if the retrieving operation is not finished or if there is no data to fetch.

Great! with that change, we can now browse on the root of the project and start the server with this command to preview our app.

yarn start

Or if you’re using npm:

npm start

You should see that the data are successfully fetched and if you click on the button, new data will be retrieved by SWR

So far, we have seen in practice the SWR library, and I hope you are finding value on it. However, it still has some features to offer. Let’s dive into these functionalities in the next section.

Other Features Of SWR

The SWR library has a bunch of handy things that simplifies the way we build React apps.

Focus Revalidation

It’s a feature that allows updating or revalidating to be precise the data when you re-focus a page or switch between tabs. And by default, this functionality is enabled, but you can disable it anyway if it does not fit your need. It can be useful especially if you have data with high-level-frequency updates.

Refetch on Interval

The SWR library allows refetching data after a certain amount of time. It can be handy when your data changes at high speed or you need to make a new request to get a piece of new information from your database.

Local Mutation

With SWR, you can set a temporary local state that will update automatically when new data are fetched(revalidation). This feature comes in play particularly when you deal with an Offline-first approach, it helps to update data easily.

Scroll Position Recovery

This feature is very handy, especially when it comes to dealing with huge lists. It allows you to recover the scroll position after getting back to the page. And in any case, it increases the usability of your app.

Dependent Fetching

SWR allows you to fetch data that depends on other data. That means it can fetch data A, and once that operation is done, it uses it to fetch data B while avoiding waterfalls. And this feature helps when you have relational data.

That said, SWR helps to increase the user experience in any matter. It has more features than that, and for many cases it’s better to use it over the Fetch API or the Axios library.

Conclusion

Throughout this article, we have seen why SWR is an awesome library. It allows remote data fetching using React Hooks and helps to simplify some advanced features out of the box such as pagination, caching data, refetching on interval, scroll position recovery, and so on. SWR is also backend agnostic which means it can fetch data from any kind of APIs or databases. In definitive, SWR increases a lot the user experience of your React apps, it has a bright future and you should keep an eye on it or better use it in your next React app.

You can preview the finished project live here.

Thanks for reading!

Next Steps

You can go on to check the following links which will give you a better understanding beyond the scope of this tutorial.