https://a.storyblok.com/f/270183/724196/1896f135b3/call-tracking-1.png

Acompanhamento de campanhas de chamadas de voz recebidas com o Mixpanel

Publicado em May 18, 2021

Tempo de leitura: 9 minutos

O acompanhamento de campanhas é essencial para qualquer campanha de marketing ou publicidade. Sem a capacidade de acompanhar com precisão o número de usuários que interagem com cada anúncio, não é possível calcular o custo por aquisição (CPA); portanto, em última análise, não é possível determinar quais campanhas são bem-sucedidas e quais estão gerando prejuízo para a empresa; CPA superior à ARPU (Receita Média por Usuário).

Could he be any more asleep?

(A área de Business Intelligence usa siglas e jargões ainda piores do que a área de tecnologia!)

Dada a enorme quantidade de conteúdo na web que é sustentada por anúncios, não é de se surpreender que as ferramentas para gerenciar campanhas online já estejam bastante maduras. Mas, quando queremos rastrear “cliques” provenientes de mídia impressa ou de outras formas de publicidade offline, precisamos recorrer a URLs promocionais exclusivas ou códigos de cupom.

No entanto, depois que o usuário inserir nossa URL promocional ou código de cupom, poderemos rastreá-lo por meio das mesmas ferramentas comprovadas de inteligência de negócios e análise que utilizamos em qualquer outra campanha online.

Mas e quanto às nossas pessoas que ligam para nós? Pode-se argumentar que os usuários que optam por ligar para nossa empresa já estão mais engajados com nossa marca do que alguém que simplesmente clicou em um link, mas as ferramentas existentes para rastrear essas interações são propensas a erros ou, no caso de equipamentos corporativos de atendimento de chamadas, têm um custo proibitivo.

O rastreamento de chamadas recebidas enfrenta a mesma dificuldade que os URLs impressos: a transição do analógico para o digital. Precisamos de um ponto de entrada exclusivo para cada campanha, algo que seja tão barato e fácil de configurar quanto um URL exclusivo, mas que nos permita rastrear nossas campanhas de chamadas recebidas em nosso CRM ou plataforma de BI já existente.

Números virtuais da Nexmo são perfeitos para essa situação. São baratos, fáceis de configurar e podemos criar um número virtual exclusivo para cada campanha, o que nos permite rastrear onde o usuário viu cada número e, por fim, qual campanha está proporcionando o melhor ROI (retorno sobre o investimento). Você também pode adquirir números locais em 66 países diferentes, para que sejam específicos de cada região, e esse número está sempre aumentando.

Requisitos

Se você quiser executar o exemplo localmente, precisará de:

  1. a Account no Mixpanel; o plano gratuito será suficiente para este exemplo

  2. uma maneira de disponibilizar sua aplicação Flask local na internet pública. Eu costumo usar o ngrok para isso durante o desenvolvimento

Algum conhecimento de Python/Flask seria útil, mas não é obrigatório. O código é bastante simples, então, mesmo que você prefira Ruby, PHP, JavaScript etc., ainda assim deverá conseguir acompanhar sem muita dificuldade.

O que queremos monitorar?

Mindmap showing what elements we want to track

A campanha de inbound

Precisamos saber qual campanha o usuário acessou. Podemos ter várias campanhas diferentes em andamento em canais distintos; por isso, precisamos identificar a campanha para que possamos associar corretamente as ações do usuário a ela.

A pessoa que ligou

O ideal seria descobrirmos o nome deles, mas isso só será possível em determinados territórios. No entanto, usando a Number Insight API , sempre devemos conseguir identificar o tipo de número de onde estão ligando, em que país estão e com que frequência ligam.

Ao usar o número de telefone do usuário como um identificador único, também podemos rastrear suas ações além desta ligação. Se, durante o cadastro em nosso site, coletarmos o número de telefone do usuário, o que podemos confirmar com a Verify API, poderemos cruzar quaisquer ações futuras que ele realizar com a ligação que fez para o nosso número virtual.

A ligação

Neste exemplo, vamos monitorar apenas as chamadas concluídas, mas poderíamos monitorar os diferentes status das chamadas, como tempo limite esgotado, falha, rejeição e linha ocupada. Outras informações que precisamos acompanhar são a duração da chamada e o custo da chamada. Com isso, podemos começar a calcular o custo por aquisição de nossos novos clientes por meio dessa campanha.

Acompanhamento de campanhas de Voice recebidas: todo o processo

process diagram showing the complete call tracking flow

O diagrama de sequência acima pode parecer um pouco intimidador, mas vamos analisá-lo parte por parte.

Atendimento de chamadas recebidas

Quando um usuário liga para um número virtual da Nexmo, a API da Nexmo solicita um objeto de controle de chamadas da Nexmo (NCCO) da URL que fornecemos. Esse arquivo JSON do NCCO conterá uma lista de ações que a Nexmo deve executar sempre que uma chamada for recebida.

A primeira ação que queremos realizar é transmitir um arquivo MP3 para quem está ligando; esse arquivo de som informará que podemos gravar a ligação.

[
  {
    "action": "stream", 
    "streamUrl": [
      "https://example.com/audio/calls-recorded.mp3"
    ]
  }
]

Gravação e encaminhamento da chamada para o nosso agente

Na segunda parte do diagrama de sequência, iniciamos a gravação da chamada e, em seguida, conectamos o chamador ao agente que está atendendo as chamadas dessa campanha.

[
  {
    "action": "stream", 
    "streamUrl": [
      "https://example.com/audio/calls-recorded.mp3"
    ]
  }, 
  {
    "action": "record", 
    "eventUrl": [
      "https://example.com/record/"
    ]
  }
]

A ação de gravação no NCCO é simples. Basta especificar a URL que deve receber uma notificação quando a gravação da chamada estiver disponível. Quando a chamada terminar, a gravação será interrompida automaticamente.

Estabelecendo a ligação

Ao usar a ação “conectar”, nosso número de origem precisa ser um número virtual da Nexmo. Nesse caso, usaremos o número da campanha de voz de entrada para a qual o usuário está ligando.

[
  {
    "action": "stream", 
    "streamUrl": [
      "https://example.com/audio/calls-recorded.mp3"
    ]
  }, 
  {
    "action": "record", 
    "eventUrl": [
      "https://example.com/record/"
    ]
  }, 
  {
    "action": "connect", 
    "endpoint": [
      {
        "number": "441632960616", 
        "type": "phone"
      }
    ], 
    "from": "441632960277"
  }
]

É possível especificar diferentes tipos de endpoints aos quais se conectar, como um WebSocket, mas como queremos fazer o proxy da chamada, vamos usar o tipo “telefone” e, em seguida, o número ao qual desejamos nos conectar.

Criando nossa primeira visualização no Flask

No exemplo, os NCCOs acima de todos os nossos valores estão codificados de forma fixa. Mas, em uma situação real, muitos desses valores mudarão dependendo do número virtual que o usuário tiver discado. Precisaremos primeiro identificar a campanha para a qual o usuário está ligando e, em seguida, atualizar o local do arquivo MP3 e o número de telefone do agente de atendimento.

Também precisamos considerar o caso em que não temos uma campanha ativa para um número. Talvez seja de um anúncio antigo, e a campanha de marketing já não esteja mais em andamento. Podemos não ter nenhum agente disponível para atender chamadas relacionadas a essa campanha, mas não queremos liberar o número virtual. Em nosso código de exemplo, usaremos a ação de conversão de texto em fala para informar ao usuário que o número não está mais ativo; no entanto, em sua aplicação em produção, você poderia redirecionar o usuário para a central telefônica principal ou realizar outra ação que proporcione uma melhor experiência ao usuário.

Vamos ver, primeiro, como encontraríamos a campanha em questão.

def get_campaign(number_to):
    Campaign = Query()
    campaigns = db.search(
        (Campaign.inbound_number == number_to) | (Campaign.redirect_number == number_to)
    )
    return campaigns[0] if campaigns else None

@app.route('/')
def answer():
    number_to = request.args.get('to')
    campaign = get_campaign(number_to)

Estamos usando o tinydb em nosso exemplo; trata-se de um mecanismo de banco de dados simples para Python, projetado para sistemas embarcados. Ele é perfeito para o nosso exemplo, pois utiliza um único arquivo plano (JSON) como banco de dados, mas você poderia facilmente substituí-lo pelo SQLAlchemy ou por outro ORM de sua escolha.

Quando a Nexmo solicita nosso NCCO, ela inclui o número chamado no formato internacional E.164 como parte da string de consulta. Usaremos esse número ao consultar nosso banco de dados para a campanha relevante; portanto, você deve garantir que também utilize o formato E.164 ao salvar as informações da sua campanha no seu banco de dados.

Nossa get_campaign função retornará a primeira campanha correspondente; caso não seja encontrada nenhuma, retornaremos None.

Respondendo com nosso objeto de controle de chamadas do Nexmo

Desde que tenhamos conseguido encontrar uma campanha correspondente nas etapas acima, preencheremos nosso NCCO com o streamUrl, from número e endpoint. Caso não consigamos encontrar uma campanha correspondente, usaremos a API de conversão de texto em fala e uma voz sintetizada para informar o usuário: “O número discado não foi reconhecido.”

if campaign:
    ncco = [
        {
            'action': 'stream',
            'streamUrl': ['https://example.com/{message}'.format(
                message=campaign['welcome_message']
            )]
        },
        {
            'action': 'record',
            'eventUrl': ['https://example.com/record/']
        },
        {
            'action': 'connect',
            'from': campaign['inbound_number'],
            'endpoint': [{
                'type': 'phone',
                'number': campaign['redirect_number']
            }]
        }
    ]
    return jsonify(ncco)
else:
    return jsonify([{
        'action': 'talk',
        'text': 'The number dialled has not been recognised. Please check and try again'
    }])

Acompanhamento das informações das chamadas recebidas

Assim que a chamada terminar, não só a gravação será concluída, como também a Nexmo acionará nosso webhook com as informações relevantes.

Esse evento concluído, no entanto, não conterá informações sobre o usuário que realizou a chamada. Para isso, precisaremos usar a API Nexmo Number Insight.

Depois de termos todas as informações necessárias — sobre qual campanha a ligação foi feita, quem ligou e os detalhes da própria ligação —, vamos armazenar essas informações no Mixpanel.

Estamos usando o Mixpanel neste exemplo, mas isso não significa que você só possa usar o Mixpanel. Envie os dados para qualquer ferramenta que desejar ou para várias Applications ao mesmo tempo usando uma ferramenta como o Segment. Não importa se você está usando o Mixpanel, o KISSmetrics, o Periscope, o Chartio, o Salesforce ou até mesmo um sistema de BI ou CRM desenvolvido sob medida. Se a ferramenta puder receber dados, você poderá usar essa mesma abordagem para rastrear suas chamadas recebidas.

@app.route('/event', methods=['POST'])
def callevent():
    event = json.loads(request.data)

    if event['status'] == 'completed':
        campaign = get_campaign(event['to'])

Em primeiro lugar, estamos especificando que esse endpoint aceita apenas POST solicitações, já que é isso que receberemos da Nexmo. O corpo dessa POST solicitação será uma string JSON; portanto, precisaremos convertê-la em um objeto Python.

Conforme mencionado acima, neste exemplo estamos interessados apenas nas chamadas com o status “concluída”. Existem muitos outros status que poderíamos receber, como “ocupado” ou “falha”, e pode ser muito importante acompanhar esses status se, por exemplo, você estivesse desenvolvendo um software para monitorar chamadas de suporte recebidas. Mas, por enquanto, vamos nos concentrar apenas nas chamadas concluídas.

Além disso, vamos rastrear apenas as solicitações relacionadas a campanhas existentes. Portanto, antes de qualquer outra coisa, vamos usar nossa get_campaign função e verificar se o usuário ligou a respeito de uma campanha ativa.

Criação dos nossos clientes Mixpanel e Nexmo

Para consultar informações sobre quem está ligando, precisaremos de uma instância do cliente da API da Nexmo para que possamos usar a Number Insight API. Seguindo a metodologia de aplicativos de 12 fatores, criei variáveis de ambiente contendo minha chave e meu segredo da API da Nexmo, bem como o token do meu projeto no Mixpanel.

mix = Mixpanel(os.environ['MIXPANEL_TOKEN'])
client = nexmo.Client(
    key=os.environ['NEXMO_API_KEY'],
    secret=os.environ['NEXMO_API_SECRET']
)

Recuperação e rastreamento de informações sobre quem está ligando

Vamos usar a Number Insight API para obter todas as informações disponíveis sobre quem está ligando. Essas informações incluirão dados como o país de onde a ligação foi feita, o tipo de rede e, quando disponível, o nome da pessoa que está ligando.

Armazenaremos essas informações juntamente com o número de telefone do usuário, que servirá como identificador exclusivo. Dessa forma, poderemos associar esse evento, bem como todos os eventos subsequentes, à mesma conta de usuário no Mixpanel. Se já existir um usuário com esse número de telefone, em vez de criar um novo perfil de usuário, o Mixpanel atualizará o perfil dele com os dados recebidos de nossa solicitação de informações sobre o número, garantindo que ele esteja sempre atualizado.

# Fetch people data
insight = client.get_advanced_number_insight(number=event['from'])
uid = event['from']

# Create/Update user in Mixpanel
mix.people_set(
    uid,
    {
        '$phone': '+' + event['from'],
        '$first_name': insight.get('first_name'),
        '$last_name': insight.get('last_name'),
        'Country': insight.get('country_name'),
        'Country Code': insight.get('country_code_iso3'),
        'Valid Number': insight.get('valid_number'),
        'Reachable': insight.get('reachable'),
        'Ported': insight.get('ported'),
        'Roaming': insight.get('roaming').get('status'),
        'Carrier Name': insight.get('current_carrier').get('name'),
        'Network Type': insight.get('current_carrier').get('network_type'),
        'Network Country': insight.get('current_carrier').get('country'),
    }
)

Também vamos usar alguns outros métodos da API do Mixpanel people_track_charge e people_increment. Usaremos esses métodos para acompanhar quanto gastamos atendendo às chamadas desse usuário e o número de vezes que ele ligou.

# Useful for Mixpanel revenue tracking
mix.people_track_charge(uid, float(data.get('price')) * -1)

# Track number of times user calls
mix.people_increment(uid, {'Number of Calls': 1})

Envio do evento “Chamada recebida” para o Mixpanel

Por fim, vamos rastrear a própria chamada. Usaremos novamente o número de telefone do chamador como identificador, para que possamos associar o evento ao usuário correto. Também vamos rastrear sobre qual campanha a pessoa ligou, para que possamos segmentar facilmente nossos dados e verificar o desempenho de cada campanha.

# Track call data in Mixpanel
mix.track(
    uid,
    'Inbound Call',
    {
        'Campaign Name': campaign['name'],
        'Duration': int(data.get('duration')),
        'Start Time': data.get('start_time'),
        'End Time': data.get('end_time'),
        'Cost': float(data.get('price'))
    }
)

Experimente você mesmo

Todo o código deste artigo está disponível no GitHub. Ele usa Python, Flask e tinydb. Portanto, certifique-se de instalar as dependências requirements.txt usando o pip.

Há também um exemplo campaigns.json: este é o arquivo usado pelo tinydb. Você precisará atualizá-lo com os valores corretos. Consulte a documentação do tinydb para saber como adicionar linhas adicionais ao seu banco de dados, caso deseje incluir mais de uma campanha.

Nexmo application creation screen

Você também precisará de um número virtual da Nexmo e um aplicativo de voz configurado. Recentemente, lançamos nosso painel de controle do aplicativo de voz; você pode ler mais sobre ele e sobre como criar um novo aplicativo de voz em nosso blog.

Depois de configurar tudo corretamente, você pode executar o aplicativo Flask com os seguintes comandos:

export FLASK_APP=app.py
flask run

Se você encontrar algum erro, tente ativar o modo de depuração no Flask antes de tentar novamente. Ah, e não se esqueça de criar as variáveis de ambiente exigidas pelos clientes do Mixpanel e do Nexmo!

export FLASK_DEBUG=1
export MIXPANEL_TOKEN="<YOUR MIXPANEL PROJECT TOKEN>"
export NEXMO_API_KEY="<YOUR NEXMO API KEY>"
export NEXMO_API_SECRET="<YOUR NEXMO API SECRET>"

E agora?

Tente adicionar notificações por SMS quando uma chamada for concluídaou substitua o rastreamento do Mixpanel pelo do Segment. Você pode ler mais sobre a Voice API e a Number Insight API usadas nos exemplos acima em nosso site para desenvolvedores. Não deixe de conferir as outras ações disponíveis nos NCCOs.

Compartilhar:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Aaron BassettEx-funcionários da Vonage

Aaron era um defensor de desenvolvedores na Nexmo. Engenheiro de software experiente e aspirante a artista digital, Aaron costuma ser visto criando coisas com código ou com eletrônica; às vezes, os dois. Geralmente, dá para perceber quando ele está trabalhando em algo novo pelo cheiro de componentes queimando no ar.