How a Global App CS Manager Understands Worldwide User Inquiries

If the current system falls short, we figure it out ourselves!
DelightRoom's avatar
Apr 05, 2021
How a Global App CS Manager Understands Worldwide User Inquiries

Introduction

What would you do if your inbox was filled with hundreds of emails in dozens of languages from all over the world?

You might think, "What kind of nonsense is that?!" But this is exactly what the POM (Product Operations Manager) group at DelightRoom faces every single day on the front lines of user communication. To tackle this, our POM group has been striving to break free from the limitations of our existing tools and find more efficient and effective workflows. Let me share the various hurdles—big and small—we encountered while trying to translate user messages, and how we ultimately overcame them.

Hitting the limits of repetitive tasks

The Product Operations Manager group (hereafter POM group) acts as the bridge connecting users and DelightRoom. One of our core responsibilities is reviewing and responding to user inquiries and feedback. Because Alarmy is a global app service, we receive hundreds of questions and bug reports daily across dozens of different languages. At DelightRoom, we manage this massive influx of feedback and inquiries using the integrated customer support software, Zendesk.

In Zendesk, every piece of user feedback is called a "ticket." Before we had an automated ticket translation system in place, our process for handling non-Korean/English tickets looked like this:

The process of translating 2 sample tickets. Converting it to a GIF makes it look even slower.
A GIF capturing the process below
  1. First, log into Zendesk and go to the filter view where pending tickets are gathered.

  2. Select a ticket to open its view. (This step takes longer to load than you'd think.)

  3. If it's not in Korean or English, select the body text. If it's a single line, triple-click to select it all; if it's multiple lines, click and drag.

  4. Once selected, the text gets translated into English via a Google Translate Chrome extension.

  5. Select the translated English text again, paste it into Zendesk's internal note section, and update the ticket to save the English version. (If we don't save it like this, we'd have to translate it all over again the next time we read it—super annoying.)

  6. Move on to the next ticket and repeat the whole process.

They say humans are creatures of habit, and sure enough, this lengthy process eventually became second nature. However, as I mentioned earlier, about 40% of those hundreds of tickets required translation. Even if we only received 100 tickets a day, we still had to repeat this cycle 40 times. Over a month, that's at least 1,200 times! Plus, the Zendesk UI is packed with features, so the loading time incurred every time we saved and moved to the next ticket really stacked up, eating away more resources than expected. It wasn't something we could just brush off by saying, "We're used to it, so it doesn't take that long."

Another downside to the old method was that it was impossible to gauge the trends of incoming tickets until a human actually translated them. For example, if ticket volume suddenly spiked to 3–4 times the usual amount, we'd have to translate all (or at least most) of them just to see if there was a common thread. In an emergency, this delay in identifying the problem is a fatal flaw.

As the Alarmy app gained more users and added new features, the volume of feedback and inquiries naturally increased. The POM group's responsibilities were also expanding bit by bit. As a result, the need to save resources spent on repetitive tasks and systemize the workflow became critical. Feeling the pinch of these limitations, I started digging a well to build an automated ticket translation system.

Everything I thought of, someone else thought of first

Unsurprisingly, the idea of "automated ticket translation" wasn't unique to me. The Zendesk Marketplace, which boasts many business partners, already offered several ticket translation apps. But back then, highly-rated apps were way too expensive given DelightRoom's massive ticket volume, and the alternatives hadn't had their quality vetted yet. I was really worried that subtle translation errors or app glitches could end up complicating our ticket response process even further.

So I wondered, what if we just used Google Translate like we were already doing? Google, which has absolutely everything you could ever need, provided a Translation API! Excited, I fired off a few API requests using Postman, an API testing tool. In an instant, the response came back with language detection info and the translated text.

The result of translating a sample Japanese phrase into English using Postman.

That's when this thought hit me.

"If we use the Google Translation API, couldn't we translate tickets perfectly tailored to our workflow, without having to rely on a complex third-party app?"

The pricing table for the Google Cloud Translation Basic plan.

Thankfully, the basic Google Translation product was incredibly cheap. In fact, it was free for up to 500,000 characters per month! I checked the character count of our historical tickets and found we didn't quite hit 500,000 a month. This gave me the confidence that we could use this API to get high-quality translations without spending a dime.

The beautiful End Picture

The final picture I envisioned when starting out was simply automating the exact process humans were already doing. If you draw that out in a very, very simple flowchart, it looks like this.

The fully evolved version of this flowchart will make an appearance at the end!

The second step seemed easy enough to solve with Google Translate. So now, I just needed Step 1 to read the body of the user's ticket (the input for Google Translate), and Step 3 to paste the internal note and update the ticket (the output from Google Translate).

Fortunately, I had tinkered with Zendesk's API a couple of times before, so finding a way wasn't too hard. It looked like I could get it done with two APIs: one to fetch ticket data and read the body text, and another to update the ticket with replies, tags, and so on.

Easier said than done

Sadly... contrary to the simple End Picture I had in mind, there were a lot more minor hurdles than expected. But where there's a will, there's a way. (Actually, where there are tons of APIs, there's a way.)

First, the part that needed translating varied entirely depending on where the ticket came from. I had to target different body locations depending on whether it was an in-app inquiry or a store review. Sure, it would have been easy to just say translate the whole body text!, but doing so would risk exploding🌋 the character count sent to the translator, pushing us over the 500,000 limit. Also, store inquiries often contained a mix of English, risking a false detection of the original language as English. (Which would completely defeat the purpose of running it through the translator in the first place. Sob.)

Left: A review from the app store / Right: Feedback submitted in-app

So for the very first step, I set it up to categorize tickets based on their source. Depending on the bucket they fell into, the script would scrape the body text from different locations. Even within this, there were a few variables, but thankfully, after a few tweaks, we were able to pinpoint exactly the parts that needed translation.

Second, I had to pre-filter cases that didn't need translation. This was also to prevent wasting money by making unnecessary API calls. And since I was running this script locally on my laptop rather than through full automation, translating every single ticket—including Korean and English ones—would have doubled the processing time.

A Pie Chart showing the language breakdown of incoming tickets.

Luckily, inquiries submitted from within the app passed along the user's configured language value. Using this info, I could filter out any starting with en- or ko-.

Top: Translation result from AppFollow / Bottom: Google Translate result

As for store reviews, they were already arriving translated via AppFollow, an intermediary service that forwards tickets to Zendesk. Because of this, I initially excluded them from translation. However, the translation quality was pretty poor, often resulting in inaccurate (and sometimes hilariously weird^^) translations. In the end, we frequently had to manually translate them again anyway. Very fortunately, AppFollow detected the original language and passed that data along. By leveraging this info for store tickets, I could exclude Korean and English tickets from the translation queue.

Third, I needed to create a way to check whether a ticket had already been translated or not. What if the script hit an error and stopped midway, or I accidentally closed my laptop...? I had to prevent the disaster of paying 2X the cost by re-translating things we had already processed.

A filter view gathering all the tickets that need translation.

The solution was this: tag every newly created ticket with "translation_needed" and create a new filter view to gather them. Out of the countless APIs Zendesk provides, one of them fetches all the ticket data within a specific view. I used this to only feed tickets tagged "translation_needed" into the script, and once translated, swapped the tag to "translation_done"—effectively filtering out everything except the tickets that newly required translation.

Every little bit adds up

I obviously didn't sit down and crank out this entire process all at once. Armed with some basic Python knowledge I picked up from college clubs and classes, I started by building the absolute simplest version. Even when I was happily using it, if I thought, 'Oh, I probably need this too!', I'd jot it down on my to-do list and invest 30 minutes (sometimes an hour) to tweak it. This step-by-step refinement is what ultimately built up the process above.

The evolved flowchart—quite complex, but now capable of 100% coverage.

Starting from in-app feedback, expanding to store tickets, and eventually covering tickets forwarded via Gmail (which have wildly irregular patterns), I completed a (semi-)automated translation system that handles 100% of the tickets managed by the POM group. In the final stretch, I even did my own version of refactoring—minimizing duplicate code and cleaning things up. Now, I run it with barely any code modifications. I was so proud of this journey that I even shared it with the Delighters at our company town hall meeting.

This isn't the end

The script I wrote was just a solution born out of the situation I was in; there might be better ways out there. Zendesk marketplace apps might improve drastically, making it much more cost-effective to just use one of those. A completely new style of ticket translation system that we can't even imagine right now might emerge. If that day comes, we might have to say goodbye to my script.

The various script files on my laptop that survived all the trial and error.

Does that make me feel like the whole scripting process was in vain? Absolutely not. Through this experience, I gained a much deeper understanding of Zendesk's system and the nature of the tickets flowing into DelightRoom. Building on this, I even gained the confidence that if a tool we use falls short, I can figure out a way to overcome it. So whatever happens, I can proudly say it wasn't a waste of time. Gaining hands-on experience utilizing various API services through endless Googling was a nice bonus, too.

To give you a sneak peek at future plans, I'm considering getting some help from our infra team to deploy this script to a server. If that happens, the translator will be humming along perfectly every weekend, holiday, and day off, without me having to run the script locally, right? Just imagining it gives me happy goosebumps.

Wrapping up

This whole process means much more than just, "We translate tickets faster and easier, making ticket management a breeze!" It proves that an operations group can implement automation without relying on an engineer's help. On top of that, it highlights the crucial role of a company that doesn't write off this kind of work as a waste of time, but instead encourages and champions it with a focus on productivity improvement. I believe this is what makes our POM group, and DelightRoom as a whole, such a special organization.

As the bridge connecting users and DelightRoom, our POM group is working hard to pave the roads and direct the traffic. With so many other workflows waiting to be tuned up beyond just automated ticket translation, please look forward to our future stories. :)

Curious about DelightRoom, a place that actively champions productivity improvements for its operations group? 👉 Take a peek at DelightRoom

Share article