An appropriate representation of the requested resource could not be found on this server

Si gestionas un sitio web con contenidos en ruso, o que esté orientado a usuarios rusos que pueden registrarse o rellenar y enviar formularios en los que se pide el email, es más que probable que estos usuarios tengan direcciones del tipo yandex.ru y que tengan problemas con tu sitio web, por ejemplo, viendo un mensaje similar a este cuando envíen el formulario de registro (o uno similar en el que deban escribir su dirección de correo electrónico)

Not Acceptable
An appropriate representation of the requested resource could not be found on this server.

La causa más probable es la configuración de seguridad de tu servidor. En el caso de un servidor que tenga activado mod_security, verás un registro como este en el log de errores del servidor:

[Tue Jan 07 22:43:13.627357 2020] [:error] [pid 6139] [client xxx.xxx.xxx.xxx:63118] [client xxx.xxx.xxx.xxx] ModSecurity: Access denied with code 406 (phase 2). Matched phrase "@yandex.ru" at ARGS:xemails. [file "/etc/modsecurity/custom/20_bruteforce.conf"] [line "78"] [id "222"] [msg "Posted SPAM domain in blacklist"] [data "blablabla@gmail.com\\x0d\\x0ablablabla@yandex.ru\\x0d\\x0ablablabla@yandex.com"] [hostname "dominio.com"] [uri "/apps/test/"] [unique_id "XkT9cBJihlIABAr@lkYXAWAz"], referer: http://dominio.com/apps/test/

El motivo del error es que el servidor encuentra la cadena de texto «yandex.ru» en los datos enviados por el formulario y bloquea la acción al identificar este dominio como spamer (como si no se mandara spam desde gmail.com o hotmail.com)

La solución

Afortunadamente, la solución es muy sencilla. Basta con echar un vistazo a la línea del log del servidor y ver el ID de la regla que está aplicando mod_security (en este caso, sería 222) y añadir una excepción a esta regla en el .htaccess de nuestro servidor.

SecRuleRemoveById 222

Puedes encontrar otros motivos (reglas de mod_security) que están bloqueando tu script, pero encontrarás la explicación igualmente en el log de errores del servidor.

Yandex Metrica Content Reports

Plugin WordPress de etiquetado JSON-LD para los informes de contenido en Yandex Metrica

Los informes de contenido en Yandex Metrica ha sido una de las muchas características que Yandex ha añadido a su herramienta de analítica web durante este 2019. Y probablemente, es la que más me gusta a fecha de hoy, más que la grabación de sesiones, o incluso más que el análisis de formularios (la que ha sido mi favorita hasta la fecha).

Si quieres saber más sobre estos informes de contenido, puedes leer un artículo que publiqué en septiembre (Informes de contenido en Yandex Metrica), aunque desde entonces ha habido novedades en esta función, como los informes de autores y temas (topics).

En este artículo presento un plugin para WordPress que te permitirá enviar datos a estos informes. Así pues, los comentarios que voy a ir haciendo están escritos pensando en que tu sitio web funciona con WordPress.

Configurando los informes

Para disponer de estos informes de contenido en tu cuenta de Metrica es necesario que hagas dos cosas:

  1. Activar estos informes en la configuración del contador de Metrica (si ya tienes insertado el código de seguimiento en tu sitio web, no hace falta que lo actualices)
  2. Empezar a enviar los datos sobre tus contenidos

Para enviar datos de tus contenidos tienes que disponer de algún tipo de marcado de datos en tu código. Para esto, puedes hacerlo con Open Graph, Microdata o JSON-LD.

Supongo que es una cuestión personal cómo hacerlo, pero la opción de microdata me parece poco práctica si ya tienes montado el sitio y el código de tu plantilla no incluye este marcado. Añadirlo puede ser algo costoso. La opción de Open Graph tampoco me convence demasiado, pues si usas este etiquetado pensando en la información que recupera Facebook cuando se comparte tu contenido, por ejemplo, te puede interesar tener algo distinto a lo que usarías para los informes de contenido.

Así pues, me quedo con JSON-LD, porque básicamente se reduce a insertar una etiqueta de SCRIPT en tu código, y esto se puede hacer fácilmente con WordPress sin tener que tocar mucho el código.

Yandex Metrica JSON-LD Schema

Así es como he llamado a un plugin para WordPress que he desarrollado, bastante básico pero funcional para lo que se necesita.

Se encarga de generar el marcado JSON-LD para que Yandex Metrica pueda mostrar los informes de contenido.

Estos son los elementos que incluye este marcado de datos:

  • Post
    • Título
    • Descripción (300 primeros caracteres)
    • URL
    • Imagen destacada
    • Categoría
    • Etiquetas
    • Fecha de publicación
    • Fecha de actualización
  • Autor
    • Nombre
    • URL
    • Avatar
  • Publisher
    • Nombre
    • URL
    • Logo

Realmente, en los informes de Yandex Metrica solo veremos parte de estos datos, pero de este modo el JSON-LD pasa la validación de las herramientas de comprobación de datos estructurados de Yandex y Google.

Lo he estado probando durante algo más de una semana en un par de sitios centrados en generar contenido, y cumple su cometido muy dignamente.

Instalación y configuración del plugin

El plugin se instala y se activa como cualquier otro plugin de WordPress. En esta primera versión tiene una configuración básica que te permite indicar los datos del elemento “publisher”. Si no configuras estos datos (nombre, url, logo) se usarán el nombre del sitio web, la URL del sitio web y una imagen sencilla generada con placeholder.com que mostrará el nombre del sitio web.

Plugins para el marcado de datos hay muchos, pero ninguno me convenció para pasarle los datos a Yandex Metrica, de ahí que preparase este. Para evitar conflictos, este plugin tiene una opción para desactivar esta característica de Yoast SEO (de momento solo incluye a este). Suelo usar este plugin y necesitaba deshabilitar esta opción para que solo se generase el JSON-LD preparado para Yandex Metrica. Si usas Yoast SEO, es recomendable marcar esta opción en la configuración.

Ahora, algunas cuestiones a tener en cuenta. Primero, si tu post tiene más de una categoría solo se pasa una. Si usas Yoast SEO y has marcado alguna de las categorías como principal, será esta. Si no, la primera categoría (recuperadas en orden alfabético). Y segunda cuestión, aunque en el JSON-LD se incluyen las etiquetas del post, tal como indica Yandex Metrica en su documentación oficial, de momento no se registran en los informes de temas (topics). No estoy seguro de si esto es un bug, porque el JSON-LD parece correcto y pasa la validación de Yandex, pero no se muestran estos temas en los informes. Si el marcado de datos lo haces como microdata, entonces funciona sin problemas.

24/06/2020: Hace ya unos días que este problema con el JSON-LD ha quedado resuelto y Yandex Metrica ya recupera las etiquetas del artículo para incluirlas en los informes de contenido.

26/06/2020: el plugin se ha publicado oficialmente en el repositorio de plugins de WordPress con el nombre de JSON-LD Schema for Yandex Metrica

Próximas versiones

Tengo algunas ideas con las que mejorar el plugin, pero por ahora hace lo que necesitaba que hiciera. Si las circunstancias lo permiten, iré añadiendo algunas mejoras en el plugin. Y por supuesto, todo comentario y opinión con ánimo constructivo será bien recibido.

Descargar Yandex Metrica JSON-LD Schema

Puedes descargar el plugin Yandex Metrica JSON-LD Schema, y si necesitas ayuda para configurar los informes de contenido, puedes dejar un comentario o contactar conmigo.

Primera versión: 02.12.2019
Publicado en el repositorio de WordPress.org: 26.06.2020

Cómo trabajar con Yandex Metrica y Logs API

Aunque Yandex Metrica permite crear segmentos, informes y dashboards personalizados, es posible que en algunos proyectos necesitemos más libertad a la hora de trabajar con los datos que registra Metrica.

Hay que recordar que Yandex Metrica no aplica muestreo y tenemos acceso a los datos en bruto de nuestros contadores.

La API de Yandex Metrica es bastante potente. He hablado sobre ella en algún evento de analítica web, está muy bien documentada y es sencilla de usar. Pero últimamente he estado probando Logs API con contadores de Metrica, y creo que las posibilidades son increíbles, ya que básicamente te llevas los datos que quieres para hacer luego lo que necesites con ellos.

Y con este artículo quiero hacerte una introducción a Logs API para que puedas realizar peticiones para generar un log con los datos que quieras. Yandex te sugiere, obviamente, que una vez tengas los datos conectes con ClickHouse, pero lo cierto es que puedes llevártelos donde quieras.

Paso 1: registra una aplicación con Yandex OAuth

Esto es obligatorio, aunque muy sencillo. Sin registrar una aplicación, no podremos obtener un token de acceso y sin el token de acceso, las llamadas a la API de Yandex (sea la de Metrica o la de Logs) nos dirán que el acceso no está autorizado.

Empieza en la página de Yandex OAuth y registra una aplicación

https://oauth.yandex.com/

Rellena todos los datos, selecciona Web services como plataforma en la que usarás la aplicación que estás registrando. Indica que la URL de retorno (Callback URL) será la de desarrollo, y marca los permisos que necesites. Para el objetivo de lo que estoy contando, basta con los permisos de acceso a las estadísticas de los contadores de Yandex Metrica.

Cuando tengas registrada la aplicación, verás que te muestra tres datos:

  • ID
  • Password
  • Callback URL

Necesitarás el ID para obtener el token con el que harás luego las llamadas a la API.

Para obtener el token, ve a esta dirección, cambiando ID por el ID de la aplicación que acabas de registrar:

https://oauth.yandex.com/authorize?response_type=token&client_id=<ID>

Con esto, obtenemos lo que Yandex llama el Debugging token, aunque si lo que vas a hacer depende únicamente de tu lado, este token de desarrollo puede valer sin más.

Al visitar esa URL, te devolverá el token de acceso, una cadena alfanumérica que nos servirá para autenticar las llamadas que haremos a la API.

Y así, ya podemos continuar preparando la parte en la que recuperaremos los datos de nuestros contadores de Metrica.

Paso 2: consulta los logs que has solicitado

Además del token de acceso, vamos a necesitar el ID del contador de Yandex Metrica del que vamos a recuperar datos. Lo tienes en el listado de códigos que tienes creados en Yandex Metrica.

https://api-metrica.yandex.net/management/v1/counter/<contadorID>/logrequests

Donde:

  • <contadorID>: identificador del código de Yandex Metrica del que quieres recuperar los datos

La llamada a la API:

$metrica_url = "https://api-metrica.yandex.net/management/v1/counter/<CONTADORID>/logrequests";

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL,$metrica_url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Authorization: OAuth <DEBUGGINGTOKEN>"));
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt ($ch, CURLOPT_TIMEOUT, 60);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$metrica_result = curl_exec ($ch);
curl_close($ch);

$metrica_output = json_decode($metrica_result);
print_r($metrica_output);

El resultado:

stdClass Object
(
    [requests] => Array
        (
            [0] => stdClass Object
                (
                    [request_id] => <REQUESTID>
                    [counter_id] => <CONTADORID>
                    [source] => hits
                    [date1] => 2019-09-01
                    [date2] => 2019-09-21
                    [fields] => Array
                        (
                            [0] => ym:pv:dateTime
                            [1] => ym:pv:URL
                            [2] => ym:pv:lastTrafficSource
                        )

                    [status] => processed
                    [size] => 59621
                    [parts] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [part_number] => 0
                                    [size] => 59621
                                )

                        )

                )

        )

)

Paso 3: consulta la viabilidad de una solicitud

Antes de solicitar formalmente que se procesen los datos que necesitemos, podemos consultar la viabilidad de nuestra petición. En el resultado de la llamada a la API encontraremos si es posible o no, y si no hay problemas, le mandaremos la solicitud en el paso siguiente.

https://api-metrica.yandex.net/management/v1/counter/<contadorID>/logrequests/evaluate? date1=<FECHA>&date2=<FECHA>&fields=<DIMENSIONES>&source=<DATOS>

Donde:

  • contadorID: identificador del código de Yandex Metrica del que quieres recuperar los datos
  • date1: desde qué día quieres los datos
  • date2: hasta qué día quieres los datos
  • fields: las dimensiones que quieres recuperar (documentación)
  • source: si quieres recuperar hits o sesiones (en función de lo que necesites, tienes a tu disposición diferentes dimensiones).

Puedes consultar la sintaxis de los campos a recuperar en la documentación de Logs API para Hits o la documentación de Logs API para Sesiones.

La llamada a la API:

$metrica_url = "https://api-metrica.yandex.net/management/v1/counter/<CONTADORID>/logrequests/evaluate?date1=2019-09-01&date2=2019-09-15&fields=ym:pv:dateTime,ym:pv:title,ym:pv:URL,ym:pv:lastTrafficSource&source=hits";

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL,$metrica_url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Authorization: OAuth <DEBUGGINGTOKEN>"));
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt ($ch, CURLOPT_TIMEOUT, 60);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$metrica_result = curl_exec ($ch);
curl_close($ch);

$metrica_output = json_decode($metrica_result);
print_r($metrica_output);

El resultado:

stdClass Object
(
    [log_request_evaluation] => stdClass Object
        (
            [possible] => 1
            [max_possible_day_quantity] => 1848612
        )

)

Paso 4: realiza la solicitud para crear un log

Una vez que hayamos comprobado que nuestra solicitud de datos se puede procesar, ya podemos enviar la solicitud formal para que se prepare nuestro log.

https://api-metrica.yandex.net/management/v1/counter/<contadorID>/logrequests?date1=<FECHA>&date2=<FECHA>&fields=<DIMENSIONES>&source=<DATOS>

Donde:

  • contadorID: identificador del código de Yandex Metrica del que quieres recuperar los datos
  • date1: desde qué día quieres los datos
  • date2: hasta qué día quieres los datos
  • fields: las dimensiones que quieres recuperar
  • source: si quieres recuperar hits o sesiones (en función de lo que necesites, tienes a tu disposición diferentes dimensiones).

Puedes consultar la sintaxis de los campos a recuperar en la documentación de Logs API para Hits o la documentación de Logs API para Sesiones.

La llamada a la API (ojo, esta tiene que ir como POST):

$metrica_url = "https://api-metrica.yandex.net/management/v1/counter/<CONTADORID>/logrequests?date1=2019-09-01&date2=2019-09-21&fields=ym:pv:dateTime,ym:pv:title,ym:pv:URL,ym:pv:lastTrafficSource&source=hits";

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL,$metrica_url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Authorization: OAuth <DEBUGGINGTOKEN>"));
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt ($ch, CURLOPT_TIMEOUT, 60);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_POST, true);
$metrica_result = curl_exec ($ch);
curl_close($ch);

$metrica_output = json_decode($metrica_result);
print_r($metrica_output);

El resultado:

stdClass Object
(
    [log_request] => stdClass Object
        (
            [request_id] => <REQUESTID>
            [counter_id] => <CONTADORID>
            [source] => hits
            [date1] => 2019-09-01
            [date2] => 2019-09-21
            [fields] => Array
                (
                    [0] => ym:pv:dateTime
                    [1] => ym:pv:title
                    [2] => ym:pv:URL
                    [3] => ym:pv:lastTrafficSource
                )

            [status] => created
        )

)

Ahora tendríamos dos logs solicitados / creados si hacemos la petición del paso 1, cada uno con un requestID diferente (obviamente).

Paso 5: consulta el estado de tu solicitud

Si hemos solicitado muchos datos, es posible que tarde un tiempo en procesar la solicitud. Con esta llamada a la API podemos comprobar si la solicitud está procesada y los datos están disponibles.

https://api-metrica.yandex.net/management/v1/counter/<contadorID>/logrequest/<requestId>

Donde:

  • contadorID: identificador del código de Yandex Metrica del que quieres recuperar los datos
  • requestID: identificador de la solicitud de log que quieres consultar

La llamada a la API:

$metrica_url = "https://api-metrica.yandex.net/management/v1/counter/<CONTADORID>/logrequest/<REQUESTID>";

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL,$metrica_url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Authorization: OAuth <DEBUGGINGTOKEN>"));
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt ($ch, CURLOPT_TIMEOUT, 60);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$metrica_result = curl_exec ($ch);
curl_close($ch);

$metrica_output = json_decode($metrica_result);
print_r($metrica_output);

El resultado:

stdClass Object
(
    [log_request] => stdClass Object
        (
            [request_id] => <REQUESTID>
            [counter_id] => <CONTADORID>
            [source] => hits
            [date1] => 2019-09-01
            [date2] => 2019-09-21
            [fields] => Array
                (
                    [0] => ym:pv:dateTime
                    [1] => ym:pv:title
                    [2] => ym:pv:URL
                    [3] => ym:pv:lastTrafficSource
                )

            [status] => processed
            [size] => 81420
            [parts] => Array
                (
                    [0] => stdClass Object
                        (
                            [part_number] => 0
                            [size] => 81420
                        )

                )

        )

)

Paso 6: descarga el log de tu solicitud

Una vez que tengamos procesada la solicitud de log, podemos disponer de los datos. Los puedes guardar en un fichero de texto, meterlos en base de datos…

https://api-metrica.yandex.net/management/v1/counter/<contadorID>/logrequest/<requestId>/part/<partNumber>/download

Donde:

  • contadorID: identificador del código de Yandex Metrica del que quieres recuperar los datos
  • requestID: identificador de la solicitud de log que quieres recuperar
  • partNumber: identificador numérico de la parte del log que quieres recuperar

La llamada a la API:

$metrica_url = "https://api-metrica.yandex.net/management/v1/counter/<CONTADORID>/logrequest/<REQUESTID>/part/0/download";

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL,$metrica_url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Authorization: OAuth <DEBUGGINGTOKEN>"));
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt ($ch, CURLOPT_TIMEOUT, 60);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$metrica_result = curl_exec ($ch);
curl_close($ch);

echo($metrica_result);

El resultado:

He pixelado la imagen, pero básicamente ya te lo imaginas… texto separado por tabuladores que puedes importar fácilmente a Excel o una base de datos tipo MySQL. A partir de aquí, imaginación para exprimir los datos.

Limitaciones

Tienes que usar el token de acceso en todas las peticiones que hagas a la API.

El volumen máximo de datos que se puede transmitir en cada solicitud es de 10 GB por cada contador de Metrica.

Los datos del día actual pueden no estar completos. Además, en algunas solicitudes puedes recibir un mensaje de error que la fecha (date2) debe ser anterior al día actual. Yandex recomienda en la documentación que user el día anterior como límite para recuperar los datos.

Más información

Metrica API
https://tech.yandex.com/metrika/

Documentación de la API de Metrica
https://tech.yandex.com/metrika/doc/api2/concept/about-docpage/

Autorización y token de acceso OAuth
https://tech.yandex.com/metrika/doc/ref/concepts/authorization-docpage/

Introducción a Logs API
https://tech.yandex.com/metrika/doc/api2/logs/intro-docpage/

Cómo hacer debug en Yandex Metrica

Si trabajas con Yandex Metrica, es posible que necesites comprobar rápidamente si tu código de seguimiento funciona correctamente, especialmente si mandas parámetros de usuario o parámetros de sesión. Una forma sencilla de hacerlo es añadir esta variable a la URL del sitio con el que estés trabajando:

?_ym_debug=1 // si no tienes variables en la URL
&_ym_debug=1 // si tienes otras variables en la URL

Así, verás en la consola del navegador el resultado de la comunicación con Metrica:

En esta captura de pantalla, tomada en la cuenta demo de Yandex Metrica, se ve cómo envía parámetros de sesión para indicar si el usuario tiene el menú lateral recogido o desplegado (luego todos estos parámetros están disponibles en los informes). En la primera de las líneas que se ve en la captura, comprobamos el pageview que envía al cargar la página.

Invalid response status: 307 con PayPal IPN Listener

Si usas la librería PayPal IPN Listener (https://github.com/Quixotix/PHP-PayPal-IPN) en algún proyecto, es posible que te haya dejado de funcionar la comunicación con PayPal y que encuentres en el log de errores una línea como esta:

[28-Jun-2018 18:12:04 Europe/Madrid] Invalid response status: 307

En junio de 2018 PayPal hizo efectivos una serie de cambios en sus servicios, y además de necesitar una URL para tu IPN que responda bajo HTTPS, tendrás que hacer este cambio para resolver el problema del 307.

En el fichero ipnlistener.php tendrás que modificar las líneas 71 y 72 (si no son estas mismas, por ahí andarán) por estas:

const PAYPAL_HOST = 'ipnpb.paypal.com';
const SANDBOX_HOST = 'ipnpb.sandbox.paypal.com';

Al menos en mi caso, el problema era este. La URL por defecto es www.paypal.com, pero PayPal recomienda usar ipnpb.paypal.com, e intuyo que ese 307 es la redirección de www a ipnpb.

Un consejo adicional para que nos apliquemos los que aún usamos PayPal IPN Listener es que actualicemos código, pues este recurso tiene ya unos cuantos años y tiene pinta de haber sido abandonado. ¿Qué alternativa a PayPal IPN Listener recomendarías?