Western Mass Hosting's Development Articles

Home / Development / Page 4

Why Responsive Web Design Is So Important

Mobile internet browsing is on the rise people!  As of this posting the number of people browsing the internet from a mobile device is up to 18% vs. a declining 82% browsing from a desktop computer.  These numbers are up 6% since this time last year. ~ http://gs.statcounter.com/#mobile_vs_desktop-ww-monthly-201209-201309 What does this…

Cookie Notice

This site utilizes cookies to improve your browsing experience, analyze the type of traffic we receive, and serve up proper content for you. If you wish to continue browsing, you must agree to allow us to set these cookies. If not, please visit another website.

PHP Twitter User Timeline Feed Renderer

Today kiddies, we’ll be giving you some code that will enable you to utilize the new Twitter API (which by the way, v1 was removed yesterday un-beknownst to yours truly).  This will use the new authentication methods now required, and pull a users Timeline feed.I’ve commented the snots out of this, so if you don’t get it or don’t understand it, please take a moment and thoroughly go through this website to familarize yourself with PHP.So, without blabbing you ears off, here ya go…  the class, how to start, and some sample code on how to use it.

How To Start:

  1. Sign Up for a Twitter account
  2. Login to Twitter
  3. Go to https://dev.twitter.com/apps
  4. Click ‘Create a New Appliction’
    1. Fill out all fields marked with a *
    2. Click ‘Create’
  5. Under ‘OAuth’ settings click ‘Create my access token’
    1. may take a few minutes for them to show up, but after a couple of minutes refresh the page and they will show up
  6. Copy the following into the associated fields below
    1. Consumer Key = $Twit->Key
    2. Consumer Secret = $Twit->Secret
    3. Access Token = $Twit->AccessToken
    4. Access Token Secret = $Twit->AccessTokenSecret
  7. Set $Twit->ScreenName to your chosen screen name
  8. Set $Twit->PostCount to the number of items you wish to return
  9. Configure the rest of the settings if you need to
  10. Have fun Programming!

Class:

<?class o7thTwitterTimeLine {	// Settings
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// Required
	public $Key = 					null; // Consumer Key Provided by Twitter
	public $Secret = 	 		 	 null; // Consumer Secret Provided by Twitter
	public $AccessToken = 			null; // Consumer Key Provided by Twitter
	public $AccessTokenSecret = 	 null; // Consumer Secret Provided by Twitter
	public $ScreenName = 		 	 null; // Screen Name of the Timeline to return - optional (but required if no User ID provided
	public $PostCount = 		 	 null; // How many posts to pull
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// Optional
	public $WrapperID = 		 	 ''; // ID of the wrapper Section (needs to be unique, per CSS rules)
	public $WrapperClass = 	 	 ''; // Class of the wrapper Section
	public $WrapperExtras = 	 	 ''; // Any extras - format: data-role="blah"; onclick="return false;"
	public $ItemID = 			 	 ''; // ID of the item Article (needs to be unique, per CSS rules)
	public $ItemClass = 		 	 ''; // Class of the item Article
	public $ItemExtras = 		 	 ''; // Any extras - format: data-role="blah"; onclick="return false;", etc...
	public $ShowPostedDate = 	 	 true; // Show the Posted On Date (or retweeted date)
	public $DateFormat = 			 1; // Format the date string: 1 = US Date/Time, 2 = UK Date/Time, 3 = Small US Date, 4 = Small UK Date, 5 = UTC (does not matter if formatting like Twitter)
	public $ShowTwitterFormatDate = true; // Show the Posted Date formatted like: 1 day ago, 1 year ago, etc...
	public $PostedDateTpl = 		 'Posted: %s by %s'; // Template format for the Posted Date, can use HTML if needed: first argument is date/time, second is screen name
	public $ShowProfileUrl = 	 	 true; // Show the Profile URL
	public $ShowProfileDetails = 	 true; // Show the profiles Location, Description, and Link if any: NOTE: If list, may not render
	public $ShowProfileImage = 	 true; // Show the profiles main Image: NOTE: If list, may not render
	public $ShowImageInPost = 		true; // If we're showing the profile image, should we show it in each post?
	public $ShowFollowerCount = 	 true; // Show the profiles follower count
	public $ShowFriendCount = 		true; // Show the profiles friends count
	public $RenderHashTagUrls = 	 true; // Parse the text for hash tags, and render them?
	public $RenderProfileUrls = 	 true; // Parse the text for profiles, and render them?
	public $RenderContentLinks = 	 true; // Parse the text looking for any links, and render them?
	public $ListOrArticles = 		 1; // Render the items as a list(1), or as Article(2) containers?
	public $OpenURLsInNewWindow = 	true; // Should we open any URLs we find in a new window?
	public $PostExtraItemContent = null; // Any extra content for each item? Can use HTML. Goes after the item, inside the wrapping.
	public $PostExtraFeedContent = null; // Any extra content for the feed? Can use HTML. Goes after the feed, inside the wrapping: NOTE: If list, may not render.
	public $PreExtraItemContent = null; // Any extra content for each item? Can use HTML. Goes before the item, inside the wrapping.
	public $PreExtraFeedContent = null; // Any extra content for the feed? Can use HTML. Goes before the feed, inside the wrapping: NOTE: If list, may not render.
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	// Twitter User Timeline API URL
	protected $APIUrl = 'https://api.twitter.com/1.1/statuses/user_timeline.json';	public function __construct(){
		if(!in_array('curl', get_loaded_extensions())){
 throw new Exception('You need to install cURL, see: http://curl.haxx.se/docs/install.html');
 }
	}	// Return it
	public function ReturnTheTimeline(){
		// Pull our feed, and return it is as an associative array
		return $this->PullTheFeed();
	}	// Render the feed, instead of just returning it
	public function RenderTheFeed(){
		// Pull our feed as an associative array
		$feed = $this->PullTheFeed();
		// Count the items returned
		$fCt = count($feed);
		$ret = null;
		// Are we opening links in a new window
		$nw = ($this->OpenURLsInNewWindow) ? ' target="_blank"' : '' ;
		// Set the container based on what is chosen in our settings
		$ret .= ($this->ListOrArticles == 1) ? '<ul id="' . $this->WrapperID . '" class="' . $this->WrapperClass . '"' . $this->WrapperExtras . '>' : '<section id="' . $this->WrapperID . '" class="' . $this->WrapperClass . '"' . $this->WrapperExtras . '>' ;
		// Pre-Feed Content
		$ret .= $this->PreExtraFeedContent;
		// section for profile details, follower & friend counts, and profile image if not in post: if allowed through our settings
		if($this->ShowProfileDetails){
			$ret .= '	<div id="profile_' . $this->WrapperID . '" class="profile_' . $this->WrapperClass . '">';
			$ret .= '		<div class="profile_name">' . $this->ScreenName . '</div>';
			// Show the Follower Count if allowed through our settings
			$ret .= ($this->ShowFollowerCount) ? '<span class="profile_followers_count">Followers: ' . $feed[0]['user']['followers_count'] . '</span>' : null;
			// Show the Friend Count if allowed through our settings
			$ret .= ($this->ShowFriendCount) ? '<span class="profile_friends_count">Friends: ' . $feed[0]['user']['friends_count'] . '</span>' : null;
			$ret .= '		<div class="profile_description">' . $feed[0]['user']['description'] . '</div>';
			$ret .= '		<div class="profile_location">' . $feed[0]['user']['location'] . '</div>';
			// Show the Profile Image if allowed through our settings
			$ret .= ($this->ShowProfileImage) ? '		<div class="profile_image"><img src="' . $feed[0]['user']['profile_image_url'] . '" alt="' . $this->ScreenName . '" /></div>' : null;
			$ret .= '		<div class="profile_link"><a href="' . $feed[0]['user']['entities']['url']['urls'][0]['expanded_url'] . '"' . $nw . '>' . $feed[0]['user']['entities']['url']['urls'][0]['expanded_url'] . '</a></div>';
			$ret .= '	</div>';	
		}
		// Feed Items
		for($i = 0; $i < $fCt; ++$i){
			// Set the Item container based on what is chosen in our settings
			$ret .= ($this->ListOrArticles == 1) ? '	<li id="' . $this->ItemID . '" class="' . $this->ItemClass . '"' . $this->ItemExtras . '>' : '	<article id="' . $this->ItemID . '" class="' . $this->ItemClass . '"' . $this->ItemExtras . '>';
			// Pre-Item Content
			$ret .= $this->PreExtraItemContent;
			// Show the Profile Image if allowed through our settings
			$ret .= ($this->ShowProfileImage && $this->ShowImageInPost) ? '<div id="" class=""><img src="' . $feed[$i]['user']['profile_image_url'] . '" alt="' . $this->ScreenName . '" /></div>' : null ;
			// Show the Profile URL if allowed through our settings
			$ret .= ($this->ShowProfileUrl) ? '<div id="profilelink_' . $this->ItemID . '" class="text_' . $this->ItemClass . '"><a href="http://twitter.com/' . $this->ScreenName . '"' . $nw . '>@' . $this->ScreenName . '</a></div>' : null;
			// Show the text of the post, formatting it necessary
			$ret .= '<div id="text_' . $this->ItemID . '" class="text_' . $this->ItemClass . '">' . $this->FormatPostText($feed[$i]['text']) . '</div>';
			// Section for the date
			if($this->ShowPostedDate){
				if(!$this->ShowTwitterFormatDate){
					// Format the date/time based on our settings
					switch($this->DateFormat){
						case 1: // US Date/Time
							$dt = date('m/d/Y h:i A', $feed[$i]['created_at']);
							break;	
						case 2: // UK Date/Time
							$dt = date('d/m/Y h:i A', $feed[$i]['created_at']);
							break;	
						case 3: // US Short Date
							$dt = date('m/d/Y', $feed[$i]['created_at']);
							break;	
						case 4: // UK Short Date
							$dt = date('d/m/Y', $feed[$i]['created_at']);
							break;	
						default:
							$dt = $feed[$i]['created_at'];
					}
				}else{
					// Format the date/time as shown on Twitter
					$dt = $this->ShowTwitterFormattedDate($feed[$i]['created_at']);
				}
				$ret .= '<div id="date_' . $this->ItemID . '" class="date_' . $this->ItemClass . '">' . sprintf($this->PostedDateTpl, $dt, $this->ScreenName) . '</div>';
			}
			// Post-Item Content
			$ret .= $this->PostExtraItemContent;
			// Close the Item container based on what is chosen in our settings
			$ret .= ($this->ListOrArticles == 1) ? '	</li>' : '	</article>' ;
		}
		// Post-Feed Content
		$ret .= $this->PostExtraFeedContent;
		// Close the container based on what is chosen in our settings
		$ret .= ($this->ListOrArticles == 1) ? '</ul>' : '</section>' ;
		return $ret;
	}	// Format post text accordingly (this just does some replacements for profiles, hashtags, and links (if allowed)
	protected function FormatPostText($txt){
		try{
			if($this->RenderProfileUrls || $this->RenderHashTagUrls || $this->RenderContentLinks){
				$ret = $txt;
				$nw = ($this->OpenURLsInNewWindow) ? ' target="_blank"' : '' ;
				// Parse any http and https links that may occur in our content
				if($this->RenderContentLinks){
					$ret = preg_replace('/http://([a-z0-9_.-+&!#~/,]+)/i', '<a href="http://$1"' . $nw . '>http://$1</a>', $ret);				
					$ret = preg_replace('/https://([a-z0-9_.-+&!#~/,]+)/i', '<a href="https://$1"' . $nw . '>https://$1</a>', $ret);				
				}
				// Parse any profile tags that may occur
				if($this->RenderProfileUrls){
					$ret = preg_replace('/[@]+([A-Za-z0-9-_]+)/', '<a href="http://twitter.com/$1"' . $nw . '>$0</a>', $ret);
				}
				// Parse any hastags that may occur
				if($this->RenderHashTagUrls){
					$ret = preg_replace('/[#]+([dw]+)/', '<a href="https://twitter.com/search?q=%23$1&src=hash"' . $nw . '>$0</a>', $ret);				
				}
				return $ret;
			}else{
				// Returnt the original if none of these are allowed through the settings
				return $txt;
			}
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}	// Format the Date
	protected function ShowTwitterFormattedDate($a) {
		try{
			$b = strtotime("now"); 
			$c = strtotime($a);
			$d = $b - $c;
			$minute = 60;
			$hour = $minute * 60;
			$day = $hour * 24;
			$week = $day * 7;
			if(is_numeric($d) && $d > 0) {
				if($d < 3) return "right now";
				if($d < $minute) return floor($d) . " seconds ago";
				if($d < $minute * 2) return "about 1 minute ago";
				if($d < $hour) return floor($d / $minute) . " minutes ago";
				if($d < $hour * 2) return "about 1 hour ago";
				if($d < $day) return floor($d / $hour) . " hours ago";
				if($d > $day && $d < $day * 2) return "yesterday";
				if($d < $day * 365) return floor($d / $day) . " days ago";
				return "over a year ago";
			}
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}		// Do the heavy lifting
	protected function PullTheFeed(){
		// Make sure the required settings
		if(!isset($this->Key) || !isset($this->Secret) || !isset($this->AccessToken) || !isset($this->AccessTokenSecret) || !isset($this->ScreenName) || !isset($this->PostCount)){
 throw new Exception('You need to set the "Required" settings in order to use this.');
		}
		// Set our CURL Options
		try{
			$opts = array(CURLOPT_HTTPHEADER => $this->Auth(),
						 CURLOPT_HEADER => false,
						 CURLOPT_URL => $this->APIUrl . '?screen_name=' . $this->ScreenName . '&count=' . $this->PostCount . '',
						 CURLOPT_RETURNTRANSFER => true,
						 CURLOPT_SSL_VERIFYPEER => false);
			// Initialize our Curl Handle
			$ch = curl_init();
			// Pass in our options
			curl_setopt_array($ch, $opts);
			// Execute the request and get back the response
			$json = curl_exec($ch);
			// Clean up...
			curl_close($ch);
			unset($opts);
			// Return an associated array (json decoded)	
			return json_decode($json, true);
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}	// Authorize Us
	protected function Auth(){
		try{
			$oauth = array(
					'screen_name' => $this->ScreenName,
					'count' => $this->PostCount,
					'oauth_consumer_key' => $this->Key,
					'oauth_nonce' => time(),
					'oauth_signature_method' => 'HMAC-SHA1',
					'oauth_token' => $this->AccessToken,
					'oauth_timestamp' => time(),
					'oauth_version' => '1.0');
			// Build the base string we will need to pass to Twitter's OAuth
			$base_info = $this->buildBaseString($this->APIUrl, 'GET', $oauth);
			$composite_key = rawurlencode($this->Secret) . '&' . rawurlencode($this->AccessTokenSecret);
			$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
			$oauth['oauth_signature'] = $oauth_signature;		
			return array($this->buildAuthorizationHeader($oauth), 'Expect:');
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}	// Build our base Auth String
	protected function buildBaseString($baseURI, $method, $params) {
		try{
			$r = array();
			ksort($params);
			foreach($params as $key => $value){
				$r[] = "$key=" . rawurlencode($value);
			}
			return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}	// Build our Authorization headers
	protected function buildAuthorizationHeader($oauth) {
		try{
			$r = 'Authorization: OAuth ';
			$values = array();
			foreach($oauth as $key => $value)
				$values[] = "$key="" . rawurlencode($value) . """;
			$r .= implode(', ', $values);
			return $r;
		}catch(Exception $e){
 throw new Exception($e->getMessage());
		}
	}	}

Sample Usage:

<?php	// Require our class
	require_once($_SERVER['DOCUMENT_ROOT'] . '/twitter/o7th.twitter.api.class.php');	// Fire up the class
	$Twit = new o7thTwitterTimeLine();	// -------------------------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------------------------
	// Required Settings
	$Twit->Key = 'XXXXXXXXXXXXXX'; // Consumer Key Provided by Twitter
	$Twit->Secret = 'XXXXXXXXXXXXXX'; // Consumer Secret Provided by Twitter
	$Twit->AccessToken = 'XXXXXXXXXXXXXX'; // Access Token Provided by Twitter
	$Twit->AccessTokenSecret = 'XXXXXXXXXXXXXX'; // Access Token Secret Provided by Twitter
	$Twit->ScreenName = 'o7thwd'; // Screen Name of the Timeline to return - optional (but required if no User ID provided
	$Twit->PostCount = 15; // How many results do we return?
	// -------------------------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------------------------
	// Optional Settings
	$Twit->WrapperID = 		 	 'o7_twit_feed_id'; // ID of the wrapper Section (needs to be unique, per CSS rules)
	$Twit->WrapperClass = 	 	 'o7_twit_feed_class'; // Class of the wrapper Section
	$Twit->WrapperExtras = 	 	 ' style="cursor:help"'; // Any extras - format: data-role="blah"; onclick="return false;"
	$Twit->ItemID = 			 	 ''; // ID of the item Article (needs to be unique per item, per CSS rules)
	$Twit->ItemClass = 		 	 'o7_twit_item_class'; // Class of the item Article
	$Twit->ItemExtras = 		 	 ' style="cursor:pointer" onclick="alert('Item Clicked!');"'; // Any extras - format: data-role="blah"; onclick="return false;", etc...
	$Twit->ShowPostedDate = 	 	 true; // Show the Posted On Date (or retweeted date)
	$Twit->DateFormat = 			 1; // Format the date string: 1 = US Date/Time, 2 = UK Date/Time, 3 = Small US Date, 4 = Small UK Date, 5 = UTC (does not matter if formatting like Twitter)
	$Twit->ShowTwitterFormatDate = true; // Show the Posted Date formatted like: 1 day ago, 1 year ago, etc...
	$Twit->PostedDateTpl = 		 'Posted: %s by %s'; // Template format for the Posted Date, can use HTML if needed: first argument is date/time, second is screen name
	$Twit->ShowProfileUrl = 	 	 true; // Show the Profile URL
	$Twit->ShowProfileDetails = 	 true; // Show the profiles Location, Description, and Link if any: NOTE: If list, may not render
	$Twit->ShowProfileImage = 	 true; // Show the profiles main Image: NOTE: If list, may not render
	$Twit->ShowImageInPost = 		true; // If we're showing the profile image, should we show it in each post?
	$Twit->ShowFollowerCount = 	 true; // Show the profiles follower count
	$Twit->ShowFriendCount = 		true; // Show the profiles friends count
	$Twit->RenderHashTagUrls = 	 true; // Parse the text for hash tags, and render them?
	$Twit->RenderProfileUrls = 	 true; // Parse the text for profiles, and render them?
	$Twit->RenderContentLinks = 	 true; // Parse the text looking for any links, and render them?
	$Twit->ListOrArticles = 		 1; // Render the items as a list(1), or as Article(2) containers?
	$Twit->OpenURLsInNewWindow = 	true; // Should we open any URLs we find in a new window?
	$Twit->PostExtraItemContent = '<strong>POST ITEM CONTENT</strong>'; // Any extra content for each item? Can use HTML. Goes after the item, inside the wrapping.
	$Twit->PostExtraFeedContent = '<strong>POST FEED CONTENT</strong>'; // Any extra content for the feed? Can use HTML. Goes after the feed, inside the wrapping: NOTE: If list, may not render.
	$Twit->PreExtraItemContent = '<strong>PRE ITEM CONTENT</strong>'; // Any extra content for each item? Can use HTML. Goes before the item, inside the wrapping.
	$Twit->PreExtraFeedContent = '<strong>PRE FEED CONTENT</strong>'; // Any extra content for the feed? Can use HTML. Goes before the feed, inside the wrapping: NOTE: If list, may not render.
	// End Settings
	// -------------------------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------------------------	// Return the associative array, so you can process it any way you like =}
	$Feed = $Twit->ReturnTheTimeline();	// Render the feed
	$RenderedFeed = $Twit->RenderTheFeed();
	echo $RenderedFeed;	// Just printing out the returned array
	echo '<hr />';
	echo '<pre>';
	print_r($Feed);
	echo '</pre>';	// Cleaning up (not really necessary though, PHP does a great job at this all by itself...
	unset($Feed, $RenderedFeed);?>

Our Privacy Policy

Last Updated: June 18th, 2025

Introduction

Western Mass Hosting (“we,” “our,” or “us”) respects the privacy of all individuals and organizations that interact with our services. This Privacy Policy establishes our practices regarding the collection, use, disclosure, and protection of personal information for visitors to our website and clients utilizing our managed hosting and WordPress services. By accessing our website or engaging our services, you acknowledge that you have read and understood this policy in its entirety.

Scope and Applicability

This Privacy Policy governs our handling of information collected through our corporate website and in the course of providing managed hosting, WordPress maintenance, and development services. In accordance with global privacy regulations, we serve as a Data Controller for information related to our business operations and client relationships. When processing data on behalf of our clients through hosted services, we act as a Data Processor under applicable data protection laws.

Information We Collect

We collect various categories of information necessary to provide and improve our services. This includes personal contact and payment details provided during account registration, technical information such as IP addresses and device characteristics for security purposes, and records of communications through support channels. For clients utilizing our hosting services, we may process end-user data stored within client websites, though we do not control or monitor the collection practices of such data.

Purpose and Legal Basis for Processing

We process personal information only when we have proper justification under applicable laws. The primary legal bases for our processing activities include the necessity to fulfill contractual obligations to our clients, our legitimate business interests in maintaining and improving our services, and in limited cases, explicit consent for specific marketing communications. We maintain detailed records of processing activities to demonstrate compliance with legal requirements.

Use of Collected Information

The information we collect serves multiple business purposes. Primarily, we use this data to deliver and maintain reliable hosting services, including server provisioning, performance monitoring, and technical support. We also utilize information for business operations such as billing, customer relationship management, and service improvement initiatives. Security represents another critical use case, where we analyze data to detect and prevent fraudulent activity or unauthorized access to our systems.

Data Sharing and Third-Party Disclosures

We engage with carefully selected third-party service providers to support our operations, including cloud infrastructure providers, payment processors, and customer support platforms. These relationships are governed by strict contractual agreements that mandate appropriate data protection measures. We may disclose information when legally required to comply with court orders, government requests, or to protect our legal rights and the security of our services.

International Data Transfers

As a global service provider, we may transfer and process data in various locations worldwide. When transferring personal data originating from the European Economic Area or other regulated jurisdictions, we implement appropriate safeguards such as Standard Contractual Clauses and rely on adequacy decisions where applicable. Our subprocessors, including AWS Lightsail, maintain robust compliance certifications to ensure the protection of transferred data.

Data Retention Practices

We retain personal information only for as long as necessary to fulfill the purposes outlined in this policy. Client account information is typically maintained for five years following service termination to comply with legal and financial reporting obligations. Backup data associated with hosting services is automatically purged after thirty days, as specified in our Terms of Service. For data processed on behalf of clients, retention periods are determined by the respective client’s policies and instructions.

Security Measures

We implement comprehensive technical and organizational security measures to protect personal information against unauthorized access, alteration, or destruction. Our security program includes network encryption protocols, regular vulnerability assessments, strict access controls, and employee training on data protection best practices. We maintain incident response procedures to address potential security breaches and will notify affected parties where required by law.

Individual Rights

Individuals whose personal data we process may exercise certain rights under applicable privacy laws. These rights may include requesting access to their information, seeking correction of inaccurate data, requesting deletion under specific circumstances, and objecting to particular processing activities. We have established procedures to handle such requests in accordance with legal requirements, typically responding within thirty days of receipt. Requests should be submitted to our designated Data Protection Officer through the contact information provided in this policy.

Cookies and Tracking Technologies

Our website employs various technologies to enhance user experience and analyze site performance. Essential cookies are used for basic functionality and security purposes, while analytics cookies help us understand how visitors interact with our site. Marketing cookies are only deployed with explicit user consent. Visitors can manage cookie preferences through their browser settings or our cookie consent tool.

Policy Updates and Notifications

We periodically review and update this Privacy Policy to reflect changes in our practices or legal obligations. Material changes will be communicated to affected clients through email notifications at least thirty days prior to implementation. Continued use of our services following such notifications constitutes acceptance of the revised policy.

Contact Information

For questions or concerns regarding this Privacy Policy or our privacy practices, please contact our Data Protection Officer at info@westernmasshosting.com or by mail at:

Western Mass Hosting
22 Orlando. St.,
Feeding Hills, MA 01030.

We take all privacy-related inquiries seriously and will respond promptly to legitimate requests. For clients with specific data processing agreements, please reference your contract for any additional terms that may apply to our handling of your data.