Skip to content

Building Offers In Lives

How we moved fast to generate a million-dollar feature

In the e-commerce world, pricing is less of a numbers game and more of an art form, especially for our sellers on Whatnot livestreams. Up until now, they’ve had to choose between auctions, where their merchandise might go for less than anticipated, or the “Buy It Now” route, which risks making the price too lofty for potential buyers.

Recently, we’ve introduced a third alternative: “Offers in Live”, affectionately called by its acronym “O.I.L”, which enables buyers to pitch their prices on listings in real-time. This new capability integrates the best of the past into our present product.

Keep reading to find out how we built and scaled this feature—solving a complex technical challenge while moving quickly, to enable more sales for our sellers.

History

When Whatnot first launched as the go-to Funko marketplace, offers were implemented as a vital transaction tool. However, it was confined to the Marketplace—a more traditional, asynchronous online shopping experience. Bringing it to Whatnot’s live interface was the next step, but we knew it wouldn’t be easy—as offers follow a fundamentally different pattern than our other purchase formats.

But why bring it to livestreams?

As a growth team, we scout for areas that can expand our product category experiences. Sellers often gauge how much buyers would pay for an item—such as a Slab—through chat, and then adjust the price accordingly. Offers in Live now productizes this process, accelerating sales and increasing turnover in a given time span. Recognizing this feature’s vast potential, we were determined to implement it promptly.

Working with legacy code, and fast

Living by the Whatnot principles of moving uncomfortably fast and prioritizing impact ruthlessly, we sought to integrate the existing Offers feature into our core livestream experience as fast as possible. Instead of focusing on overhauling the existing architecture, our main goal was to validate the idea and deliver value to our users.

Thanks to our Marketplace team’s Universal Listings architecture, which abstracts Listings from their location, we circumvented touching the core Listing model.

The Order model, which contains all the transaction logic, already encapsulated the offers. We have an existing placeOffer GraphQL mutation, used by our marketplace. This mutation does what you’d expect—creates an offer, which is defined as an Order object with a particular style. Orders have two properties in particular that we’re interested in—channel_reference, which can be a livestream_id, and a sales_type, which can be LIVESTREAM. By setting those as the values, we’ve now connected the offer to a livestream! This means that when a seller enters a livestream, they can see all their offers. Moreover, when they view their dashboard after the fact, they can see accepted offers as processed orders and proceed to ship them to eager buyers. For buyers though, we have to make sure they’re paying the right, and best, price.

More money, more problems

Given its fundamental deviation from other purchase formats, offer pricing posed a formidable challenge. For auctions, standard “Buy It Now” purchases, or giveaways, the process is straightforward—a buyer makes a transaction and the product is now theirs.

However, for offers, the flow is like this:

  1. buyers first make an offer
  2. seller can accept, reject, or counteroffer
  3. If a counter offer, the buyer can accept or reject
  4. The buyer only gets charged when an offer is accepted or a counteroffer is accepted

This led to some problems with pricing calculations. Imagine if a buyer makes two offers on two distinct listings, and they are quoted a potential price for each offer. What if the user has credits and we apply them on the first offer, but only the second offer gets accepted? The credits would not be used. Or, take the example of shipping bundling. What if we apply the special bundled discounted shipping price to the second offer because the buyer made a previous offer, but only the second offer gets accepted? This would mean we undercharged the buyer for shipping. Conversely, if we just choose not to do these calculations, then offers are inherently more expensive for buyers.

As a result, we balanced user expectations with technical capability, by adjusting the price at the time of the transaction.

Initially, when we place an offer, we process it as if it was the first offer (unless we know another purchase has already been processed). But when an offer is accepted we recalculate the total price, which involves a process of:

1. Checking if that user made any other purchases in a live, and if so, seeing if we could apply our bundled shipping price

2. Checking if credits could be applied to an offer purchase if they exist

3. Any other price optimizations

If the price is different, we delete the old Payment model that was created, create a new one, and actually process it.

But, in addition to solving pricing, we also had to figure out how to make offers feel “live”.

Bring me back to…live

Adding “liveness”, or real-time functionality, was tricky as well. For Whatnot, our real-time events are powered by our “live-service”, which is written in Elixir. In this service, listings have a counterpart of “Live Products” in a Dynamo database. Adding extra fields to the model, and extra parameters to the API calls, for offers would be a gargantuan task. Instead, we opted to create our own event, aptly named offer, to represent actions on an offer. This event specified the buyer and the seller, as well as the appropriate order_id and listing_id. To broadcast the event, our backend repository, named main-backend, which is written in Python, simply made REST API calls to live-service when the client made offer-related mutations.

In particular, the actions we defined were:

  1. create
  2. counter_offer
  3. reject
  4. accept

When the client received an offer event through the live-socket, it could read one of these actions and show a banner to the involved parties, so they can be informed. We also used this event to update the live store and show a persistent notification on the store button so that both sellers and buyers could be aware of the state of any offers pertaining to them.

Defining our event like this keeps the payload lightweight, and allows the client to decide optimally how to load more data about the offers, depending on the state of the current UI.

Thus, our “live-service” merely relays notifications on offers, enabling clients to update the UI in real-time, thereby injecting that special touch into Whatnot livestreams.

Client-side experience

In the UI, we created a delightful product experience that made sure offers were easily accessible. Buyers can make offers from the pinned product view, the live store, or the listing detail page.

On the eve of our launch, we realized sellers were being overwhelmed with offer requests on the mobile interface. While this was a great problem to have, we knew we needed a way for sellers to manage these offers with ease. But how? Web!

We spent a whole day grinding out the seller-side interface for offers on our Web platform, hacking away in ReactJS. In particular, we wanted to build the most important actions for the median seller. So, we built a simple modal that showed a list of Listings with offers to the seller. From this view, the seller could either accept the highest offer or counter all offers—unlocking most of the desired functionality that was available on mobile. By the time the sun rose the next day, it was completed, and we let sellers know of its existence. This way, sellers could manage offers on our web platform, while simultaneously using mobile to stream and do other important tasks for their show. In one stream, one of our first adopters got 750+ offers, representing $15K+ of GMV.

Striking O.I.L

At launch, our top sellers took Offers in Live for a test drive and loved it! Within a week, 77% of our sellers adopted this feature for some of their listings. Buyers relished the thrill of “winning a deal,” while sellers enjoyed the brisk pace of inventory clearance. In the two short months since its launch, Offers in Live has raked in millions of dollars in GMV and continues to grow.

The lessons learned reaffirm our principles—prioritizing impact and maintaining speed can unlock immense value.

Looking into the future

Offers in Live is just the tip of the iceberg of innovative features brought forward by the growth team, and we have many more exciting projects coming in the future.

If solving problems that improve the seller and buyer experience interests you, join us at https://whatnot.com/careers.

Marketplace

Every shop has a story. Help us build the platform behind it.