Implement Client-side Bug Reporting with UserSnap
Key Takeaways
- UserSnap is a tool that allows users to report bugs directly from a website by marking up a screenshot and sending all data in the JavaScript console. It can be integrated into a client’s website to expedite bug reporting and resolution.
- Developers can also use UserSnap to gather server-side errors and logs. By using a simple class, they can record all errors and logs needed for debugging, which can then be passed to UserSnap. This allows for faster and more efficient bug fixes.
- UserSnap also provides additional information such as screen size, browser version, OS, and installed browser plugins. This feature can be turned on only when needed, and its availability can be limited through methods such as IP filtering or opening a dev.* subdomain.
Imagine the following scenario: your clients visit the website (let’s imagine this one) and see anything but the expected result. The normal reaction is to call you (at the most inappropriate time) and ask you to fix it ASAP, because they’re losing money.
How can we help the user report the bug as accurately as possible?

The bug
Let’s have a really simple JSON request and an error to be able to reproduce our case:
<span>$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}'; </span> <span>//we will simulate the json data, but imagine that this is the normal data exchanged daily between your client’s website and a 3rd party API </span> <span>$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php'); </span><span>curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); </span><span>curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', </span> <span>'Content-Length: ' . strlen($json_data))); </span> <span>//the normal CURL request, nothing strange here: </span><span>$result = curl_exec($ch); </span> <span>//receiving the data back </span><span>$f_data = json_decode($result,true); </span> <span>//showing a greeting with the output </span><span>echo “Welcome”. $f_data['username'];</span>
If you visit the test website now, you will notice that there’s a problem.
The question is – how can the client report it faster with all the data you need to fight the bug:
- Json data,
- Server-side Javascript and XmlHttpsRequest errors,
- Some core PHP errors
- …and meta data.
An interesting solution for gathering this information is UserSnap. A widget that lets your users mark up a screenshot of the site they’re on and send you everything that’s in the JavaScript console. PHP errors don’t end up there, though, do they? Let’s make them. First, we’ll gather the server side errors.
Gathering Errors
Let’s add some more code to the example in order to see how we can collect the data we need. Introducing a really simple class to help us:
<span><span><? </span></span><span><span>class SendToUsersnap </span></span><span><span>{ </span></span><span> <span>var $m; </span></span><span> <span>//Save all logs in an array. You can use an even more elegant approach but right now I need it to be simple for the sake of this tutorial. </span></span><span> <span>function log ( $data, $type ) { </span></span><span> </span><span> <span>if( is_array( $data ) || is_object( $data ) ) { </span></span><span> <span>$this->m[]= "console.".$type."('PHP: ".json_encode($data)."');"; </span></span><span> <span>} else { </span></span><span> <span>$this->m[] = "console.".$type."('PHP: ".$data."');"; </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>// Print all logs that have been set from the previous function. Let’s keep it simple. </span></span><span> <span>function out (){ </span></span><span> <span>for ($i=0;$i<count($this->m);$i++) </span></span><span> <span>{ </span></span><span> <span>echo $this->m[$i]."\n"; </span></span><span> <span>} </span></span><span> </span><span> </span><span> <span>} </span></span><span><span>}</span></span>
Now let’s use this class to record all errors and logs we may need.
<span>require_once('Usersnap.class.php'); </span> <span>$s = new SendToUsersnap; </span> <span>$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}'; </span> <span>$s->log('Initializing the JSON request',"info"); </span> <span>$s->log($json_data,"log"); </span> <span>$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php'); </span> <span>curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); </span> <span>curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); </span> <span>curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); </span> <span>curl_setopt($ch, CURLOPT_HTTPHEADER, array( </span> <span>'Content-Type: application/json', </span> <span>'Content-Length: ' . strlen($json_data))); </span> <span>$result = curl_exec($ch); </span> <span>$f_data = json_decode($result,true); </span> <span>echo 'Welcome'. $f_data['usersname']; </span> <span>$s->log($f_data,"log"); </span> <span>$s->log(error_get_last(),"error");</span>
Pass it to UserSnap
Let’s add the UserSnap code snippet at the end of our page and see what happens. (You may need an account to use this widget. Usersnap offers free licenses for Open Source projects and a free testing period for commercial ones.
<span><span><span><script</span> type<span>="text/javascript"</span>></span><span> </span></span><span><span> <span>(function() { </span></span></span><span><span> <span>var s = document.createElement("script"); </span></span></span><span><span> s<span>.type = "text/javascript"; </span></span></span><span><span> s<span>.async = true; </span></span></span><span><span> s<span>.src = '//api.usersnap.com/load/'+ </span></span></span><span><span> <span>'your-api-key-here.js'; </span></span></span><span><span> <span>var x = document.getElementsByTagName('script')[0]; </span></span></span><span><span> x<span>.parentNode.insertBefore(s, x); </span></span></span><span><span> <span>})(); </span></span></span><span><span> </span></span><span><span> <span>var _usersnapconfig = { </span></span></span><span><span> <span>loadHandler: function() { </span></span></span><span><span> <span><span><?php </span></span></span></span><span><span><span> <span>//just print all errors collected from the buffer. </span></span></span></span><span><span><span> <span>$s->out(); ?></span> </span></span></span><span><span> <span>} </span></span></span><span><span> <span>}; </span></span></span><span><span></span><span><span></script</span>></span></span>
Note: You would do this in a view template in a real framework, but as we’re not using a real MVC app here, we’re skipping that part.
The user will see a “report bug” button on the page and will write you a message like “it’s not working, fix it asap”. Generally, this would be useless information, but this time, we get this gorgeous error log attached, too:
Now you can see that there is initialization in place:
<span>$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}'; </span> <span>//we will simulate the json data, but imagine that this is the normal data exchanged daily between your client’s website and a 3rd party API </span> <span>$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php'); </span><span>curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); </span><span>curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', </span> <span>'Content-Length: ' . strlen($json_data))); </span> <span>//the normal CURL request, nothing strange here: </span><span>$result = curl_exec($ch); </span> <span>//receiving the data back </span><span>$f_data = json_decode($result,true); </span> <span>//showing a greeting with the output </span><span>echo “Welcome”. $f_data['username'];</span>
You can see the data we will send – the same as usual
<span><span><? </span></span><span><span>class SendToUsersnap </span></span><span><span>{ </span></span><span> <span>var $m; </span></span><span> <span>//Save all logs in an array. You can use an even more elegant approach but right now I need it to be simple for the sake of this tutorial. </span></span><span> <span>function log ( $data, $type ) { </span></span><span> </span><span> <span>if( is_array( $data ) || is_object( $data ) ) { </span></span><span> <span>$this->m[]= "console.".$type."('PHP: ".json_encode($data)."');"; </span></span><span> <span>} else { </span></span><span> <span>$this->m[] = "console.".$type."('PHP: ".$data."');"; </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>// Print all logs that have been set from the previous function. Let’s keep it simple. </span></span><span> <span>function out (){ </span></span><span> <span>for ($i=0;$i<count($this->m);$i++) </span></span><span> <span>{ </span></span><span> <span>echo $this->m[$i]."\n"; </span></span><span> <span>} </span></span><span> </span><span> </span><span> <span>} </span></span><span><span>}</span></span>
And you can see the output. Yes, the problem is there. Obviously there is an auth problem.
<span>require_once('Usersnap.class.php'); </span> <span>$s = new SendToUsersnap; </span> <span>$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}'; </span> <span>$s->log('Initializing the JSON request',"info"); </span> <span>$s->log($json_data,"log"); </span> <span>$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php'); </span> <span>curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); </span> <span>curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); </span> <span>curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); </span> <span>curl_setopt($ch, CURLOPT_HTTPHEADER, array( </span> <span>'Content-Type: application/json', </span> <span>'Content-Length: ' . strlen($json_data))); </span> <span>$result = curl_exec($ch); </span> <span>$f_data = json_decode($result,true); </span> <span>echo 'Welcome'. $f_data['usersname']; </span> <span>$s->log($f_data,"log"); </span> <span>$s->log(error_get_last(),"error");</span>
You can get even the core PHP errors to help you with the debugging.
<span><span><span><script</span> type<span>="text/javascript"</span>></span><span> </span></span><span><span> <span>(function() { </span></span></span><span><span> <span>var s = document.createElement("script"); </span></span></span><span><span> s<span>.type = "text/javascript"; </span></span></span><span><span> s<span>.async = true; </span></span></span><span><span> s<span>.src = '//api.usersnap.com/load/'+ </span></span></span><span><span> <span>'your-api-key-here.js'; </span></span></span><span><span> <span>var x = document.getElementsByTagName('script')[0]; </span></span></span><span><span> x<span>.parentNode.insertBefore(s, x); </span></span></span><span><span> <span>})(); </span></span></span><span><span> </span></span><span><span> <span>var _usersnapconfig = { </span></span></span><span><span> <span>loadHandler: function() { </span></span></span><span><span> <span><span><?php </span></span></span></span><span><span><span> <span>//just print all errors collected from the buffer. </span></span></span></span><span><span><span> <span>$s->out(); ?></span> </span></span></span><span><span> <span>} </span></span></span><span><span> <span>}; </span></span></span><span><span></span><span><span></script</span>></span></span>
Your client will only have to click the button once and you will get everything you need to fight the bug faster:
- Errors and Logs (as shown above)
- Annotated screenshot – if the problem is more complex than this simple example
- Screen size, Browser version, OS and the plugins installed in the browser
Of course you can turn this feature on only when your client needs it. To limit the availability of the widget, add an IP filter or a query param barrier, open a dev.* subdomain, etc.
Conclusion
This is not a script-monitoring tool and will not deliver information automatically when and if the problem appears. This approach will work only if an user or a client reports a bug and you as a developer or QA need more info on how to fight the bug. Imagine it as a remote debugger, but for client-side errors events and data you send from PHP to JavaScript.
I’d love to answer all of your questions! Leave your feedback below!
Frequently Asked Questions (FAQs) about Client-Side Bug Reporting with Usersnap
How does Usersnap work for client-side bug reporting?
Usersnap is a visual bug tracking tool that allows users to report bugs directly from their web applications. It works by capturing screenshots of the issue along with important browser information, which are then sent to the development team. This eliminates the need for back-and-forth communication and speeds up the bug fixing process. Usersnap also integrates with popular project management and communication tools, making it a versatile solution for various teams.
What are the key features of Usersnap?
Usersnap offers several key features that make it a powerful tool for bug reporting. These include screenshot capturing, browser information collection, console log recording, and user feedback collection. It also offers integrations with popular tools like Slack, Jira, and Trello, among others. Additionally, Usersnap provides an API for further customization and integration with other systems.
How can I integrate Usersnap into my web application?
Integrating Usersnap into your web application is straightforward. You need to sign up for a Usersnap account, create a new project, and then add the provided JavaScript code to your web application. This code will load the Usersnap widget on your application, allowing users to report bugs directly.
Can I customize the Usersnap widget?
Yes, Usersnap provides a range of customization options for the widget. You can change the color, text, and position of the widget to match your brand. You can also customize the feedback form to collect specific information from your users. All these can be done through the Usersnap dashboard or via the API.
How does Usersnap help in improving the quality of my web application?
By providing a simple and efficient way for users to report bugs, Usersnap helps you identify and fix issues faster. The visual feedback and detailed browser information help your development team understand and reproduce the issues easily. This leads to quicker bug fixes and improvements, thereby enhancing the overall quality of your web application.
What is the Usersnap API and how can I use it?
The Usersnap API is a set of programming interfaces that allow you to interact with Usersnap programmatically. You can use the API to create, update, and manage projects, as well as to customize the Usersnap widget. The API is RESTful and uses standard HTTP methods, making it easy to integrate with your existing systems.
How does Usersnap handle user privacy?
Usersnap takes user privacy seriously. The tool does not track user activity or collect personal data without consent. All data collected is securely stored and only used for the purpose of bug reporting. Usersnap is also compliant with GDPR and other privacy regulations.
Can I use Usersnap for mobile bug reporting?
Yes, Usersnap supports mobile bug reporting. The Usersnap widget is responsive and works well on mobile devices. This allows your users to report bugs directly from their mobile browsers, providing you with valuable feedback for improving your mobile web application.
How does Usersnap compare to other bug reporting tools?
Usersnap stands out for its visual feedback and detailed browser information, which make bug reporting and fixing more efficient. It also offers a range of customization options and integrations with popular tools. While other tools may offer similar features, Usersnap’s simplicity and versatility make it a preferred choice for many teams.
What support does Usersnap offer?
Usersnap offers comprehensive support to its users. This includes detailed documentation, API reference, and examples to help you get started and make the most of the tool. Usersnap also provides email support for any queries or issues you may have.
The above is the detailed content of Implement Client-side Bug Reporting with UserSnap. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











There are four main error types in PHP: 1.Notice: the slightest, will not interrupt the program, such as accessing undefined variables; 2. Warning: serious than Notice, will not terminate the program, such as containing no files; 3. FatalError: the most serious, will terminate the program, such as calling no function; 4. ParseError: syntax error, will prevent the program from being executed, such as forgetting to add the end tag.

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

In PHP, password_hash and password_verify functions should be used to implement secure password hashing, and MD5 or SHA1 should not be used. 1) password_hash generates a hash containing salt values to enhance security. 2) Password_verify verify password and ensure security by comparing hash values. 3) MD5 and SHA1 are vulnerable and lack salt values, and are not suitable for modern password security.

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

HTTP request methods include GET, POST, PUT and DELETE, which are used to obtain, submit, update and delete resources respectively. 1. The GET method is used to obtain resources and is suitable for read operations. 2. The POST method is used to submit data and is often used to create new resources. 3. The PUT method is used to update resources and is suitable for complete updates. 4. The DELETE method is used to delete resources and is suitable for deletion operations.

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

In PHPOOP, self:: refers to the current class, parent:: refers to the parent class, static:: is used for late static binding. 1.self:: is used for static method and constant calls, but does not support late static binding. 2.parent:: is used for subclasses to call parent class methods, and private methods cannot be accessed. 3.static:: supports late static binding, suitable for inheritance and polymorphism, but may affect the readability of the code.

PHP handles file uploads through the $\_FILES variable. The methods to ensure security include: 1. Check upload errors, 2. Verify file type and size, 3. Prevent file overwriting, 4. Move files to a permanent storage location.
