85

Many analytic and tracking tools are requesting 1x1 GIF image (web bug, invisible for the user) for cross-domain event storing/processing.

Why to serve this GIF image at all? Wouldn't it be more efficient to simply return some error code such as 503 Service Temporary Unavailable or empty file?

Update: To be more clear, I'm asking why to serve GIF image data when all information required has been already sent in request headers. The GIF image itself does not return any useful information.

Yahel
  • 37,023
  • 22
  • 103
  • 153
Viliam
  • 4,404
  • 3
  • 28
  • 30

8 Answers8

72

Doug's answer is pretty comprehensive; I thought I'd add in an additional note (at the OP's request, off of my comment)

Doug's answer explains why 1x1 pixel beacons are used for the purpose they are used for; I thought I'd outline a potential alternative approach, which is to use HTTP Status Code 204, No Content, for a response, and not send an image body.

204 No Content

The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant.

Basically, the server receives the request, and decides to not send a body (in this case, to not send an image). But it replies with a code to inform the agent that this was a conscious decision; basically, its just a shorter way to respond affirmatively.

From Google's Page Speed documentation:

One popular way of recording page views in an asynchronous fashion is to include a JavaScript snippet at the bottom of the target page (or as an onload event handler), that notifies a logging server when a user loads the page. The most common way of doing this is to construct a request to the server for a "beacon", and encode all the data of interest as parameters in the URL for the beacon resource. To keep the HTTP response very small, a transparent 1x1-pixel image is a good candidate for a beacon request. A slightly more optimal beacon would use an HTTP 204 response ("no content") which is marginally smaller than a 1x1 GIF.

I've never tried it, but in theory it should serve the same purpose without requiring the gif itself to be transmitted, saving you 35 bytes, in the case of Google Analytics. (In the scheme of things, unless you're Google Analytics serving many trillions of hits per day, 35 bytes is really nothing.)

You can test it with this code:

var i = new Image(); 
i.src = "http://httpstat.us/204";
Yahel
  • 37,023
  • 22
  • 103
  • 153
  • 12
    These lesser known HTTP status codes (203, 204, 205) are gold, really. They should see more use than they do at present. – You Jul 10 '11 at 22:53
  • 1
    nice one--info i can put to use, in fact. +1 from me. – doug Jul 11 '11 at 02:25
  • 1
    let me see if i can summarize--the HTTP response code approach involves the *same* client request; the only difference is that the server, rather than return the 1x1 gif (and a 200, i suppose) instead, returns a 204 back to the client? – doug Jul 12 '11 at 11:14
  • 2
    How would you request for that thing that returns a 204 response code though? – Jürgen Paul Jan 09 '13 at 10:38
  • @XuqiciAcerto Example in PHP: header("status: 204"); (or the other call) header("HTTP/1.0 204 No Response"); (see http://www.php.net/manual/en/function.header.php#32569) – rodrigo-silveira Mar 01 '13 at 17:55
  • google's image proxy in gmail will return a 404 when it get's a 204 response code. a 404 imag will look ugly and more importantly if it was setting any cookies they wont get set. – user566245 Sep 01 '14 at 20:29
  • If your server is flexible you can set the response headers to JSON and send 'OK' with HTTP code 200. ;) – Vikram Tiwari Sep 25 '14 at 13:46
  • 1
    The one issue I find with using the 204 response code is that it triggers the onerror event handler of Image, not the onload. I could not find a way to distinguish a successful report from a failed report with this method – odedbd Feb 18 '16 at 09:05
  • 3
    I don't understand why image. Why not return an empty string? – Weishi Z May 25 '16 at 23:19
67

First, i disagree with the two previous answers--neither engages the question.

The one-pixel image solves an intrinsic problem for web-based analytics apps (like Google Analytics) when working in the HTTP Protocol--how to transfer (web metrics) data from the client to the server.

The simplest of the methods described by the Protocol, the simplest (at lest the simplest method that includes a request body) is the GET request. According to this Protocol method, clients initiate requests to servers for resources; servers process those requests and return appropriate responses.

For a web-based analytics app, like GA, this uni-directional scheme is bad news, because it doesn't appear to allow a server to retrieve data from a client on demand--again, all servers can do is supply resources not request them.

So what's the solution to the problem of getting data from the client back to the server? Within the HTTP context there are other Protocol methods other than GET (e.g., POST) but that's a limited option for many reasons (as evidenced by its infrequent and specialized use such as submitting form data).

If you look at a GET Request from a browser, you'll see it is comprised of a Request URL and Request Headers (e.g., Referer and User-Agent Headers), the latter contains information about the client--e.g., browser type and version, browser langauge, operating system, etc.

Again, this is part of the Request that the client sends to the server. So the idea that motivates the one-pixel gif is for the client to send the web metrics data to the server, wrapped inside a Request Header.

But then how to get the client to Request a resource so it can be "tricked" into sending the metrics data? And how to get the client to send the actual data the server wants?

Google Analytics is a good example: the ga.js file (the large file whose download to the client is triggered by a small script in the web page) includes a few lines of code that directs the client to request a particular resource from a particular server (the GA server) and to send certain data wrapped in the Request Header.

But since the purpose of this Request is not to actually get a resource but to send data to the server, this resource should be a small as possible and it should not be visible when rendered in the web page--hence, the 1 x 1 pixel transparent gif. The size is the smallest size possible, and the format (gif) is the smallest among the image formats.

More precisely, all GA data--every single item--is assembled and packed into the Request URL's query string (everything after the '?'). But in order for that data to go from the client (where it is created) to the GA server (where it is logged and aggregated) there must be an HTTP Request, so the ga.js (google analytics script that's downloaded, unless it's cached, by the client, as a result of a function called when the page loads) directs the client to assemble all of the analytics data--e.g., cookies, location bar, request headers, etc.--concatenate it into a single string and append it as a query string to a URL (*http://www.google-analytics.com/__utm.gif*?) and that becomes the Request URL.

It's easy to prove this using any web browser that has allows you to view the HTTP Request for the web page displayed in your browser (e.g., Safari's Web Inspector, Firefox/Chrome Firebug, etc.).

For instance, i typed in valid url to a corporate home page into my browser's location bar, which returned that home page and displayed it in my browser (i could have chosen any web site/page that uses one of the major analytics apps, GA, Omniture, Coremetrics, etc.)

The browser i used was Safari, so i clicked Develop in the menu bar then Show Web Inspector. On the top row of the Web Inspector, click Resources, find and click the utm.gif resource from the list of resources shown on the left-hand column, then click the Headers tab. That will show you something like this:

Request URL:http://www.google-analytics.com/__utm.gif?
           utmwv=1&utmn=1520570865&
           utmcs=UTF-8&
           utmsr=1280x800&
           utmsc=24-bit&
           utmul=enus&
           utmje=1&
           utmfl=10.3%20r181&

Request Method:GET
Status Code:200 OK

Request Headers
    User-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 
                 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1

Response Headers
    Cache-Control:private, no-cache, no-cache=Set-Cookie, proxy-revalidate
    Content-Length:35
    Content-Type:image/gif
    Date:Wed, 06 Jul 2011 21:31:28 GMT

The key points to notice are:

  1. The Request was in fact a request for the utm.gif, as evidenced by the first line above: *Request URL:http://www.google-analytics.com/__utm.gif*.

  2. The Google Analytics parameters are clearly visible in the query string appended to the Request URL: e.g., utmsr is GA's variable name to refer to the client screen resolution, for me, shows a value of 1280x800; utmfl is the variable name for flash version, which has a value of 10.3, etc.

  3. The Response Header called Content-Type (sent by the server back to the client) also confirms that the resource requested and returned was a 1x1 pixel gif: Content-Type:image/gif

This general scheme for transferring data between a client and a server has been around forever; there could very well be a better way of doing this, but it's the only way i know of (that satisfies the constraints imposed by a hosted analytics service).

doug
  • 69,080
  • 24
  • 165
  • 199
  • 3
    @doug Fabulous answer. I wish I'd written it :) It might be worth throwing in a note about potentially being able to use `HTTP Status Code 204` for a response. See this: http://code.google.com/speed/page-speed/docs/rtt.html I've never tried it, but in theory it should serve the same purpose without requiring the gif itself to be transmitted. `var i=new Image(); i.src = "http://sharedcount.com/test/beacon.gif";` is an example, but I'm not sure if it would present any browser issues. – Yahel Jul 10 '11 at 15:12
  • 10
    This is not worst answer ever because it's not answer :) I asked why to serve the GIF image at all, since the data required has been already sent with the request. – Viliam Jul 10 '11 at 18:57
  • 2
    I don't want to be too negative, sorry. This is nice explanation of web bug. But why to serve the GIF data back? – Viliam Jul 10 '11 at 19:04
  • @yahelc: that's great. Consider it to add as an answer for others. As a comment it's almost invisible. – Viliam Jul 10 '11 at 19:07
  • @Villiam sure, just added it. – Yahel Jul 10 '11 at 22:44
  • @doug I added it as a stand-alone answer. Let me know if that makes it clearer; I want the answer to be grokkable :) – Yahel Jul 11 '11 at 02:21
14

Some browsers may display an error icon if the resource could not load. It makes debugging/monitoring the service also a little bit more complicated, you have to make sure that your monitoring tools treat the error as a good result.

OTOH you don't gain anything. The error message returned by the server/framework is typically bigger then the 1x1 image. This means you increase your network traffic for basically nothing.

Ulrich Dangel
  • 4,515
  • 3
  • 22
  • 30
  • 1
    the reason that analytics apps (e.g., Google Analytics, Yahoo Analytics, Omniture, et al.) place a 1x1 pixel gif image on the web page has absolutely *nothing* to do with "debugging" the app. – doug Jul 10 '11 at 06:51
  • 3
    @doug - I think the point mru is making there is that if you deliberately return error codes, then you have to differentiate between "true" error codes, and error codes you meant to return. So the moral of the story is, never return an error code as a result when that result is what is intended. –  Jul 10 '11 at 08:32
  • 3
    I doubt error response would be larger than GIF image - note that 200 OK is response as well sent with the GIF image. – Viliam Jul 10 '11 at 18:50
  • 2
    @Villiam most environments do not just return the error code but also a nicely styled html page describing the error/providing more information. – Ulrich Dangel Jul 10 '11 at 19:12
9

Because such a GIF has a known presentation in a browser - it's a single pixel, period. Anything else presents a risk of visually interfering with the actual content of the page.

HTTP errors could appear as oversized frames of error text or even as a pop-up window. Some browsers may also complain if they receive empty replies.

In addition, in-page images are one of the very few data types allowed by default in all broswers. Anything else may require explicit user action to be downloaded.

thkala
  • 84,049
  • 23
  • 157
  • 201
  • 1
    your answer doe not say anything about the purpose for serving the resource--i.e., why does a resource need to be served at all? Your answer is directed to the question "why serve a 1x1 gif instead of another kind of image format? That's a trivial question with a trivial answer (i.e., gif format has a smaller size on a pixel-by-pixel basis than jpeg, png, tiff, etc.) – doug Jul 10 '11 at 08:32
  • You can invoke GIF loading with Javascript Image object. It won't report any errors back to the user. – Viliam Jul 10 '11 at 18:52
  • @Villiam By really returning the image you can also track browsers with no javascript enabled, just put the image tag into ` – Ulrich Dangel Jul 10 '11 at 19:19
4

This is to answer the OP's question - "why to serve GIF image data..."

Some users will put a simple img tag to call your event logging service -

<img src="http://www.example.com/logger?event_id=1234">

In this case, if you don't serve an image, the browser will show a placeholder icon that will look ugly and give the impression that your service is broken!

What I do is, look for the Accept header field. When your script is called via an img tag like this, you will see something like following in the header of the request -

Accept: image/gif, image/*
Accept-Encoding:gzip,deflate
...

When there is "image/"* string in the Accept header field, I supply the image, otherwise I just reply with 204.

Harmeet
  • 556
  • 5
  • 10
2

Well the major reason is to attach the cookie to it so if users go from one side to another we still have the same element to attach cookie to.

2

@Maciej Perliński is basically correct, but I feel a detailed answer will be beneficial.

why 1x1 GIF and not a 204 No-Content status code?

204 No-Content enables the server to omit all response headers (Content-Type, Content-Length, Content-Encoding, Cache-Control etc...) and return an empty response body with 0 bytes (and saving a lot of unneeded bandwidth).

Browsers know to respect 204 No-Content responses, and not to expect/wait for response headers and response body.

if the server needs to set any response header (e.g. cache-control or cookie), he cannot use 204 No-Content because browsers will ignore any response header by design (according to the HTTP protocol spec).

why 1x1 GIF and not a Content-Length: 0 header with 200 OK status code?

Probably a mix of several issues, just to name a few:

  • legacy browsers compatibility
  • MIME type checks on browsers, 0 bytes is not a valid image.
  • 200 OK with 0 bytes might not be fully supported by intermediate proxy servers and VPNs
0

You don't have to serve an image if you are using the Beacon API (https://w3c.github.io/beacon/) implementation method.

An error code would work if you have access to the log files of your server. The purpose of serving the image is to obtain more data about the user than you normally would with a log file.

fauverism
  • 1,970
  • 3
  • 33
  • 59